This is an R Markdown Notebook for analysis using data on the DC Bus System (WMATA Metrobus). The data were obtained here:
https://planitmetro.com/2016/11/16/data-download-metrobus-vehicle-location-data/
Control + Alt + Shift + m = rename in scope
Load the packages to be used.
package ‘maptools’ was built under R version 3.2.5
Get the Bus data.
First let’s check the working directory.
getwd()
[1] "/Users/mdturse/Desktop/Analytics/DCMetroBus"
Then, actually get the data.
The working directory was changed to /Users/mdturse/Desktop/Analytics/DCMetroBus/Bus AVL Oct 2016 inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the the working directory for notebook chunks.cannot open file '20161003MetrobusAVL.txt': No such file or directoryError in file(file, "rt") : cannot open the connection
Put the daily data together.
AllDays <- bind_rows(list(Oct03Raw, Oct04Raw, Oct05Raw, Oct06Raw, Oct07Raw),
.id = c("group")
)
# dim(AllDays)
str(AllDays)
Deleting old data frames.
for (i in 3:7){
rm(list = ls(pattern = paste0("Oct0", i, "Raw")
)
)
message("Deleting Oct0", i, "Raw")
}
Updating variable types.
Then, sorting the data and adding a RowNumber (to be used for identifying rows later in the analyses.)
rm(i)
AllDays$group <- factor(AllDays$group)
AllDays$Route_Direction <- factor(AllDays$Route_Direction)
AllDays$Event_Time <- as.POSIXct(AllDays$Event_Time, format = "%m-%d-%y %I:%M:%S %p")
AllDays$Departure_Time <- as.POSIXct(AllDays$Departure_Time, format = "%m-%d-%y %I:%M:%S %p")
str(AllDays)
AllDays_Sorted <- arrange(AllDays,
Bus_ID,
Event_Time
) %>%
mutate(RowNum_OG = row_number() # this is useful in identify the row later on
)
rm(AllDays)
str(AllDays_Sorted)
# View(head(AllDays_Sorted, 100))
Inspecting the values of Stop_ID, and finding that it can take the values “” (blank) and “NULL”.
View(group_by(AllDays_Sorted,
Stop_ID
) %>%
summarise(
Cnt = n()
) %>%
arrange(Stop_ID)
)
View(filter(AllDays_Sorted,
is.na(Stop_ID) |
Stop_ID == "" |
Stop_ID == "NULL"
) %>%
arrange(Stop_Desc)
)
Creating a table of distinct Stop_Desc values when Stop_ID is “” (blank) or “NULL”.
StopID_New <- filter(AllDays_Sorted,
is.na(Stop_ID) |
Stop_ID == "" |
Stop_ID == "NULL"
) %>%
select(Stop_ID, Stop_Desc) %>%
distinct() %>%
arrange(Stop_ID, Stop_Desc) %>%
mutate(StopID_New = 1:nrow(.)
)
View(StopID_New)
Creating a full updated table by filling in StopID_New for when Stop_ID is “” (blank) or NULL.
AllDays_StopIDNew <- left_join(AllDays_Sorted,
select(StopID_New,
Stop_Desc,
StopID_New
),
by = c("Stop_Desc" = "Stop_Desc")
) %>%
mutate(StopID_Clean = ifelse(is.na(StopID_New),
Stop_ID,
StopID_New
),
StopID_Indicator = factor(ifelse(is.na(StopID_New),
"ID_OK",
"ID_Bad"
)
)
)
rm(StopID_New)
rm(AllDays_Sorted)
str(AllDays_StopIDNew)
# View(tail(AllDays_StopIDNew, 500))
# View(filter(AllDays_StopIDNew,
# Stop_Desc == "METROWAY ANNNOUCEMNT CORR"
# )
# )
Lat Long stats for pulling in Zip codes later.
LL_Stats <- group_by(AllDays_StopIDNew,
StopID_Clean
) %>%
summarise(Lat_Mean = mean(Latitude, na.rm = TRUE),
Lat_Med = median(Latitude, na.rm = TRUE),
Lng_Mean = mean(Longitude, na.rm = TRUE),
Lng_Med = median(Longitude, na.rm = TRUE)
) %>%
mutate(Lat_MeaLessMed = Lat_Mean - Lat_Med,
Lng_MeaLessMed = Lng_Mean - Lng_Med,
RowNum = row_number()
)
str(LL_Stats)
summary(LL_Stats)
View(head(arrange(LL_Stats,
Lat_MeaLessMed
),
500
)
)
View(head(arrange(LL_Stats,
desc(Lat_MeaLessMed)
),
500
)
)
View(head(arrange(LL_Stats,
Lng_MeaLessMed
),
500
)
)
View(head(arrange(LL_Stats,
desc(Lng_MeaLessMed)
),
500
)
)
Pulling in Zip Code data from api.geonames.org.
# URL EXAMPLE:
# http://api.geonames.org/findNearbyPostalCodesJSON?lat=38.89560&lng=-76.94873&radius=0&username=supermdat
url_1 <- "http://api.geonames.org/findNearbyPostalCodesJSON?lat="
url_2 <- "&lng="
url_3 <- "&radius=0&username="
username <- "supermdat"
# need to group in bunches as http://api.geonames.org limits pulls to 2000 per hour
##### Store everything in multiple lists
pages1 <- list()
system.time(
# for(j in 0:5){
# for(k in ((max_row_per_hr*j) + 1):(max_row_per_hr*(j+1)
# )
# ){
#
# }
# }
for(i in 1:1000){
lat <- filter(LL_Stats,
RowNum == i
) %>%
select(Lat_Med)
lng <- filter(LL_Stats,
RowNum == i
) %>%
select(Lng_Med)
APIData1 <- fromJSON(paste0(url_1,
lat,
url_2,
lng,
url_3,
username
),
flatten = TRUE
)
message("Retrieving Zip Code ", i)
pages1[[i]] <- APIData1$postalCodes
# Sys.sleep(3900)
}
)
# class(APIData1)
# class(APIData2$postalCodes)
# str(APIData1)
# head(APIData1)
# class(pages1)
# str(pages1)
# nrow(page1)
# ncol(page1)
# pages1[[1199]]
# pages1[[2051]]
##### Combine the lists into one page
Zips1 <- rbind.pages(pages1[sapply(pages1, length) > 0])
##### Combine all pages
Zips_All <- bind_rows(Zips0,
Zips1,
Zips2,
Zips3,
Zips4,
Zips5,
Zips6,
Zips7,
Zips8,
Zips9,
Zips10,
# Zips1_a,
.id = "id"
) %>%
mutate(UniqueLatLng = paste(lat, lng, sep = "__")
)
# str(Zips_All)
# View(head(Zips_All))
# str(LL_Stats)
LL_Stats_UnqLatLng <- mutate(LL_Stats,
UniqueLatLng = paste(Lat_Med, Lng_Med, sep = "__")
)
# str(LL_Stats_UnqLatLng)
# View(head(LL_Stats_UnqLatLng))
LL_StatsZips <- left_join(LL_Stats_UnqLatLng,
Zips_All,
by = c("UniqueLatLng" = "UniqueLatLng")
)
str(LL_StatsZips)
# View(head(LL_StatsZips))
# Not sure whey these couldn't be found (why they're NA)
View(filter(LL_StatsZips,
is.na(postalCode)
)
)
Join to create one dataset that also includes Zip variables.
rm(url_1, url_2, url_3, username, pages0, pages1, pages2, pages3, pages4, pages5, pages6, pages7, pages8, pages9, pages10, i, lat, lng, APIData0, APIData1, APIData2, APIData3, APIData4, APIData5, APIData6, APIData7, APIData8, APIData9, APIData10, LL_Stats, LL_Stats_UnqLatLng)
AllDays_Zips <- left_join(AllDays_StopIDNew,
LL_StatsZips,
by = c("StopID_Clean" = "StopID_Clean")
) %>%
rename(Stop_State = adminCode1,
Stop_County = adminName2,
Stop_City = placeName,
Stop_Zip = postalCode
)
rm(AllDays_StopIDNew, LL_StatsZips)
str(AllDays_Zips)
Updating variable types.
AllDays_Zips$Stop_State <- factor(AllDays_Zips$Stop_State)
AllDays_Zips$Stop_County <- factor(AllDays_Zips$Stop_County)
AllDays_Zips$Stop_Zip <- factor(AllDays_Zips$Stop_Zip)
AllDays_Zips$Stop_City <- factor(AllDays_Zips$Stop_City)
AllDays_Zips$distance <- as.numeric(AllDays_Zips$distance)
AllDays_Zips$countryCode <- factor(AllDays_Zips$countryCode)
AllDays_Zips$adminName1 <- factor(AllDays_Zips$adminName1)
str(AllDays_Zips)
Feature engineering.
Inspecting incidences of consecutive Stop_IDs. This is done because investigation showed that many conseutive events occurr at the same Stop_ID, but with various Dwell_Times, Odometer_Distances, etc. All of which affect calculations and analyses.
Create data on the runs (consecutive Stop_IDs).
StopID_Runs <- rle(AllDays_Zips$StopID_Clean)
StopID_Runs$ends <- cumsum(StopID_Runs$lengths)
StopID_Runs$starts <- ifelse(is.na(lag(StopID_Runs$ends)
),
1,
lag(StopID_Runs$ends) + 1
)
str(StopID_Runs)
# class(StopID_Runs)
#
# StopID_Runs_df <- data.frame(unclass(StopID_Runs))
# str(StopID_Runs_df)
# class(StopID_Runs_df)
# rm(StopID_Runs_df)
Trying to link data on RunsGroups with the original data (AllDays_Sorted). The goal is to select only one record per RunsGroup - that being the record with the longest Dwell_Time.
I attempted this computation using both data.frames (dplyr) and data.tables (data.table). However, with 2,809,062 rows in one dataset and 3,119,443 rows in the other dataset, the current computation time is over 5 days…so I’m trying a different strategy to only select the first record in a run.
# Create a RunsGroup variable for each run
# StopID_Runs_df$RunsGroup <- paste0("g", seq(1:nrow(StopID_Runs_df)
# )
# )
#
# str(StopID_Runs_df)
# head(StopID_Runs_df, 25)
# tail(StopID_Runs_df, 25)
#
# StopID_Runs_df <- StopID_Runs_df %>%
# mutate(RowNum = row_number()
# )
#
# str(StopID_Runs_df)
# head(StopID_Runs_df, 25)
# tail(StopID_Runs_df, 25)
#
#
# # Converting to data.tables for, hopefully, improved performance (speed) in computation
# StopID_Runs_dt <- data.table(StopID_Runs_df)
# setkey(StopID_Runs_dt, RowNum)
# str(StopID_Runs_dt)
#
# AllDays_Sorted_dt <- data.table(AllDays_Sorted)
# setkey(AllDays_Sorted_dt, RowNum_OG)
# str(AllDays_Sorted_dt)
# # rm(AllDays_Sorted_dt)
#
#
# # Actual loop to perform the computations and link to original data (AllDays_Sorted_dt)
# GroupData <- list()
# for(i in 1:nrow(StopID_Runs_dt)
# ) {
# assign(paste0("group_", i),
# StopID_Runs_dt[RowNum == i, RunsGroup]
# )
#
# ##### The code below is the same code as above, but done with dplyr #####
#
# # assign(paste0("group_", i),
# # filter(StopID_Runs_df,
# # RowNum == i
# # ) %>%
# # select(RunsGroup)
# # )
#
# assign(paste0("group_", i, "_start"),
# StopID_Runs_dt[RowNum == i, starts]
# )
#
# assign(paste0("group_", i, "_end"),
# StopID_Runs_dt[RowNum == i, ends]
# )
#
# assign(paste0("group_", i, "_rows"),
# AllDays_Sorted_dt[RowNum_OG >= as.numeric(get(paste0("group_", i, "_start")
# )
# ) &
# RowNum_OG <= as.numeric(get(paste0("group_", i, "_end")
# )
# ),
# RunsGroup := as.character(get(paste0("group_", i)
# )
# )
# ]
#
# ##### The code below is the same as the code above, but done with dplyr #####
#
# # filter(AllDays_Sorted,
# # between(RowNum_OG,
# # as.numeric(get(paste0("group_", i, "_start")
# # )
# # ),
# # as.numeric(get(paste0("group_", i, "_end")
# # )
# # )
# # )
# # ) %>%
# # mutate(RunsGroup = as.character(get(paste0("group_", i)
# # )
# # )
# # )
# )
#
# GroupData[[i]] <- get(paste0("group_", i, "_rows"))
#
# message("Processing Group ", i, " of 2,809,062")
# }
#
#
# GroupData_df <- rbind.fill(GroupData)
# str(GroupData_df)
# head(GroupData_df)
# tail(GroupData_df)
# # rm(GroupData_df)
#
#
# group_1
# group_1_start
# group_1_end
# group_1_rows
# group_2_rows
# group_3_rows
# group_50_rows
# str(group_50_rows)
# group_2809062_rows
# GroupData[[1]]
# GroupData[[50]]
#
#
# ##### Testing Area (Below) #####
# ##### Testing Area (Below) #####
# ##### Testing Area (Below) #####
#
# # head(StopID_Runs$starts, 20)
# # head(AllDays_NewOrder$Stop_ID, 20)
# #
# #
# # dat <- as.data.frame(c(1,1,7,7,7,9,6,8,2,2,2,1,1,1,1,1))
# # colnames(dat)[1] <- "dat"
# # r <- rle(dat$dat)
# # dat$run <- rep(r$lengths, r$lengths)
# # dat$runLag <- lag(dat$run)
# # dat$cond <- rep(r$values, r$lengths)
# # dat
# # View(dat)
When consecutive Stop_ID occurrs, only take the first occurrence. This is done because the computation time to select only the record with the longest Dwell_Time for each run was too long (over 5 days).
This is probably less than ideal with regards to Dwell_Time, but should not make much difference for calculations of travel time, speed, etc.
AllDays_FirstStopID <- AllDays_Zips[StopID_Runs$starts, ]
dim(AllDays_Zips)
dim(AllDays_FirstStopID)
nrow(AllDays_Zips) - nrow(AllDays_FirstStopID)
rm(AllDays_Zips, StopID_Runs)
str(AllDays_FirstStopID)
Feature engineering.
Creating new variables.
AllDays_AddVars <- mutate(AllDays_FirstStopID,
Odometer_Distance_Mi = Odometer_Distance / 5280, #5,280 feet in 1 mile
Dwell_Time2 = as.numeric(Departure_Time - Event_Time),
Event_Time_Yr = as.integer(year(Event_Time)),
Event_Time_Mth = as.integer(month(Event_Time)),
Event_Time_Date = day(Event_Time),
Event_Time_Day = wday(Event_Time, label = TRUE),
Event_Time_Hr = hour(Event_Time),
Event_Time_Min = minute(Event_Time),
Event_Time_HrGroup = factor(ifelse(Event_Time_Hr < 3,
"Group0_2",
ifelse(Event_Time_Hr < 6,
"Group3_5",
ifelse(Event_Time_Hr < 9,
"Group6_8",
ifelse(Event_Time_Hr < 12,
"Group9_11",
ifelse(Event_Time_Hr < 15,
"Group12_14",
ifelse(Event_Time_Hr < 18,
"Group15_17",
ifelse(Event_Time_Hr < 21,
"Group18_20",
ifelse(Event_Time_Hr < 24,
"Group21_23"
)))))))),
levels = c("Group0_2",
"Group3_5",
"Group6_8",
"Group9_11",
"Group12_14",
"Group15_17",
"Group18_20",
"Group21_23"
),
ordered = TRUE
)
)
rm(AllDays_FirstStopID)
str(AllDays_AddVars)
# group_by(AllDays_AddVars,
# Event_Time_HrGroup
# ) %>%
# summarise(Cnts = n()
# )
# View(head(filter(AllDays_AddVars,
# Event_Time_Hr == 0
# ),
# 50
# )
# )
# View(head(AllDays_AddVars, 50))
Feature engineering.
Creating more variables. Creating a BusEvent row number for future identification purposes. Then, creating various variables to analyze distance traveled and speed.
AllDays_BusDay <- group_by(AllDays_AddVars,
Bus_ID,
Event_Time_Date
) %>%
mutate(BusDay_EventNum = row_number(), # used to identify Bus movements on a particular date
Route_Lag1 = lag(Route), # used in future analyses to identify Route changes
RouteAlt_Lag1 = lag(RouteAlt), # used in future analyses to identify RouteAlt (direction) changes
Odometer_Distance_Lag1 = lag(Odometer_Distance),
Latitude_L1 = lag(Latitude),
Longitude_L1 = lag(Longitude),
# Lat_Radian = Latitude*pi/180,
# Long_Radian = Longitude*pi/180,
# Lat_Radian_L1 = lag(Lat_Radian),
# Long_Radian_L1 = lag(Long_Radian),
# accounting for potential negative distances
TravelDistance_Ft = ifelse(Odometer_Distance > Odometer_Distance_Lag1,
Odometer_Distance - Odometer_Distance_Lag1,
NA
),
TravelDistance_Mi = TravelDistance_Ft / 5280, #5,280 feet in 1 mile
# TravelDistance_Mi2 = gcd.hf(long1 = Long_Radian_L1,
# lat1 = Lat_Radian_L1,
# long2 = Long_Radian,
# lat2 = Lat_Radian
# ),
TravelDistance_Mi_Hvrs =
# ifelse((is.na(Longitude_L1) | is.na(Latitude_L1)
# ),
# NA,
distHaversine(cbind(Longitude_L1, Latitude_L1),
cbind(Longitude, Latitude)
) * 0.000621371, # 0.000621371 miles = 1 meter
# accounting for potential negative times
TravelTime_Sec = as.numeric(ifelse(Event_Time > lag(Departure_Time),
Event_Time - lag(Departure_Time),
NA
)
),
TravelTime_Hr = TravelTime_Sec / 3600, # 3,600 seconds in 1 hour
# accounting for potential negative or zero travel times
SpeedAvg_Mph = ifelse(TravelTime_Hr > 0,
TravelDistance_Mi / TravelTime_Hr,
NA
),
Start_ID = lag(StopID_Clean),
Start_Desc = lag(Stop_Desc),
StartStop_ID = ifelse(is.na(Start_ID),
paste("NULL", StopID_Clean, sep = "--"),
paste(Start_ID, StopID_Clean, sep = "--")
)
) %>%
as.data.frame()
rm(AllDays_AddVars)
str(AllDays_BusDay)
# summary(AllDays_BusDay)
# View(tail(AllDays_BusDay, 50))
Inspecting for issues with StartStop_ID (where the value is either NA or contains NULL). They ONLY exist when BusDay_EventNum = 1 (which is by design). So everything looks OK.
View(group_by(AllDays_BusDay,
StartStop_ID
) %>%
summarise(
Cnt = n()
) %>%
arrange(desc(Cnt)
)
)
View(filter(AllDays_BusDay,
(is.na(StartStop_ID) |
str_detect(StartStop_ID, "NULL")
) &
BusDay_EventNum != 1
)
)
Stats (quantiles) overall for TravelDistance_Mi.
Quantiles_dt <- AllDays_BusDay %>%
mutate(TD_Mi_q2 = quantile(x = TravelDistance_Mi, probs = 0.02, na.rm = TRUE),
TD_Mi_q98 = quantile(x = TravelDistance_Mi, probs = 0.98, na.rm = TRUE),
TT_Sec_q2 = quantile(x = TravelTime_Sec, probs = 0.02, na.rm = TRUE),
TT_Sec_q98 = quantile(x = TravelTime_Sec, probs = 0.98, na.rm = TRUE),
TT_Hr_q2 = quantile(x = TravelTime_Hr, probs = 0.02, na.rm = TRUE),
TT_Hr_q98 = quantile(x = TravelTime_Hr, probs = 0.98, na.rm = TRUE)
) %>%
data.table()
Stats <- Quantiles_dt %>%
mutate(TD_Mi_Mean = mean(TravelDistance_Mi, na.rm = TRUE),
TD_Mi_Mean_F = mean(TravelDistance_Mi[TD_Mi_q2 <= TravelDistance_Mi & TravelDistance_Mi <= TD_Mi_q98],
na.rm = TRUE
),
TD_Mi_Med = median(TravelDistance_Mi, na.rm = TRUE),
TD_Mi_Med_F = median(TravelDistance_Mi[TD_Mi_q2 <= TravelDistance_Mi & TravelDistance_Mi <= TD_Mi_q98],
na.rm = TRUE
),
TD_Mi_Cnt = sum(!is.na(TravelDistance_Mi)
),
TD_Mi_Cnt_F = sum(!is.na(TravelDistance_Mi[TD_Mi_q2 <= TravelDistance_Mi & TravelDistance_Mi <= TD_Mi_q98]
)
),
TT_Sec_Mean = mean(TravelTime_Sec, na.rm = TRUE),
TT_Sec_Mean_F = mean(TravelTime_Sec[TT_Sec_q2 <= TravelTime_Sec & TravelTime_Sec <= TT_Sec_q98],
na.rm = TRUE
),
TT_Sec_Med = median(TravelTime_Sec, na.rm = TRUE),
TT_Sec_Med_F = median(TravelTime_Sec[TT_Sec_q2 <= TravelTime_Sec & TravelTime_Sec <= TT_Sec_q98],
na.rm = TRUE
),
TT_Sec_Cnt = sum(!is.na(TravelTime_Sec)
),
TT_Sec_Cnt_F = sum(!is.na(TravelTime_Sec[TT_Sec_q2 <= TravelTime_Sec & TravelTime_Sec <= TT_Sec_q98]
)
),
TT_Hr_Mean = mean(TravelTime_Hr, na.rm = TRUE),
TT_Hr_Mean_F = mean(TravelTime_Hr[TT_Hr_q2 <= TravelTime_Hr & TravelTime_Hr <= TT_Hr_q98],
na.rm = TRUE
),
TT_Hr_Med = median(TravelTime_Hr, na.rm = TRUE),
TT_Hr_Med_F = median(TravelTime_Hr[TT_Hr_q2 <= TravelTime_Hr & TravelTime_Hr <= TT_Hr_q98],
na.rm = TRUE
),
TT_Hr_Cnt = sum(!is.na(TravelTime_Hr)
),
TT_Hr_Cnt_F = sum(!is.na(TravelTime_Hr[TT_Hr_q2 <= TravelTime_Hr & TravelTime_Hr <= TT_Hr_q98]
)
)
) %>%
data.frame()
rm(AllDays_BusDay)
rm(Quantiles_dt)
str(Stats)
# View(head(Stats, 50))
Stats for StartStop_ID.
Quantiles_SS_dt <- group_by(Stats,
StartStop_ID
) %>%
mutate(TD_Mi_SS_q5 = quantile(x = TravelDistance_Mi, probs = 0.05, na.rm = TRUE),
TD_Mi_SS_q95 = quantile(x = TravelDistance_Mi, probs = 0.95, na.rm = TRUE),
TT_Sec_SS_q5 = quantile(x = TravelTime_Sec, probs = 0.05, na.rm = TRUE),
TT_Sec_SS_q95 = quantile(x = TravelTime_Sec, probs = 0.95, na.rm = TRUE),
TT_Hr_SS_q5 = quantile(x = TravelTime_Hr, probs = 0.05, na.rm = TRUE),
TT_Hr_SS_q95 = quantile(x = TravelTime_Hr, probs = 0.95, na.rm = TRUE)
) %>%
data.table()
Stats_StSt <- group_by(Quantiles_SS_dt,
StartStop_ID
) %>%
mutate(TD_Mi_SS_Mean = mean(TravelDistance_Mi, na.rm = TRUE),
TD_Mi_SS_Mean_F = mean(TravelDistance_Mi[TD_Mi_SS_q5 <= TravelDistance_Mi & TravelDistance_Mi <= TD_Mi_SS_q95],
na.rm = TRUE
),
TD_Mi_SS_Med = median(TravelDistance_Mi, na.rm = TRUE),
TD_Mi_SS_Med_F = median(TravelDistance_Mi[TD_Mi_SS_q5 <= TravelDistance_Mi & TravelDistance_Mi <= TD_Mi_SS_q95],
na.rm = TRUE
),
TD_Mi_SS_Cnt = sum(!is.na(TravelDistance_Mi)
),
TD_Mi_SS_Cnt_F = sum(!is.na(TravelDistance_Mi[TD_Mi_SS_q5 <= TravelDistance_Mi & TravelDistance_Mi <= TD_Mi_SS_q95]
)
),
TT_Sec_SS_Mean = mean(TravelTime_Sec, na.rm = TRUE),
TT_Sec_SS_Mean_F = mean(TravelTime_Sec[TT_Sec_SS_q5 <= TravelTime_Sec & TravelTime_Sec <= TT_Sec_SS_q95],
na.rm = TRUE
),
TT_Sec_SS_Med = median(TravelTime_Sec, na.rm = TRUE),
TT_Sec_SS_Med_F = median(TravelTime_Sec[TT_Sec_SS_q5 <= TravelTime_Sec & TravelTime_Sec <= TT_Sec_SS_q95],
na.rm = TRUE
),
TT_Sec_SS_Cnt = sum(!is.na(TravelTime_Sec)),
TT_Sec_SS_Cnt_F = sum(!is.na(TravelTime_Sec[TT_Sec_SS_q5 <= TravelTime_Sec & TravelTime_Sec <= TT_Sec_SS_q95]
)
),
TT_Hr_SS_Mean = mean(TravelTime_Hr, na.rm = TRUE),
TT_Hr_SS_Mean_F = mean(TravelTime_Hr[TT_Hr_SS_q5 <= TravelTime_Hr & TravelTime_Hr <= TT_Hr_SS_q95],
na.rm = TRUE
),
TT_Hr_SS_Med = median(TravelTime_Hr, na.rm = TRUE),
TT_Hr_SS_Med_F = median(TravelTime_Hr[TT_Hr_SS_q5 <= TravelTime_Hr & TravelTime_Hr <= TT_Hr_SS_q95],
na.rm = TRUE
),
TT_Hr_SS_Cnt = sum(!is.na(TravelTime_Hr)),
TT_Hr_SS_Cnt_F = sum(!is.na(TravelTime_Hr[TT_Hr_SS_q5 <= TravelTime_Hr & TravelTime_Hr <= TT_Hr_SS_q95]
)
)
) %>%
data.frame()
rm(Stats)
rm(Quantiles_SS_dt)
str(Stats_StSt)
# View(head(Stats_StSt, 50))
Stats for StartStop_ID with Event_Time_HrGroup.
Quantiles_SSHG_dt <- group_by(Stats_StSt,
StartStop_ID,
Event_Time_HrGroup
) %>%
mutate(TD_Mi_SSHG_q5 = quantile(x = TravelDistance_Mi, probs = 0.05, na.rm = TRUE),
TD_Mi_SSHG_q95 = quantile(x = TravelDistance_Mi, probs = 0.95, na.rm = TRUE),
TT_Sec_SSHG_q5 = quantile(x = TravelTime_Sec, probs = 0.05, na.rm = TRUE),
TT_Sec_SSHG_q95 = quantile(x = TravelTime_Sec, probs = 0.95, na.rm = TRUE),
TT_Hr_SSHG_q5 = quantile(x = TravelTime_Hr, probs = 0.05, na.rm = TRUE),
TT_Hr_SSHG_q95 = quantile(x = TravelTime_Hr, probs = 0.95, na.rm = TRUE)
) %>%
data.table()
Stats_StSt_HrGrp <- group_by(Quantiles_SSHG_dt,
StartStop_ID,
Event_Time_HrGroup
) %>%
mutate(TD_Mi_SSHG_Mean = mean(TravelDistance_Mi, na.rm = TRUE),
TD_Mi_SSHG_Mean_F = mean(TravelDistance_Mi[TD_Mi_SSHG_q5 <= TravelDistance_Mi & TravelDistance_Mi <= TD_Mi_SSHG_q95],
na.rm = TRUE
),
TD_Mi_SSHG_Med = median(TravelDistance_Mi, na.rm = TRUE),
TD_Mi_SSHG_Med_F = median(TravelDistance_Mi[TD_Mi_SSHG_q5 <= TravelDistance_Mi & TravelDistance_Mi <= TD_Mi_SSHG_q95],
na.rm = TRUE
),
TD_Mi_SSHG_Cnt = sum(!is.na(TravelDistance_Mi)
),
TD_Mi_SSHG_Cnt_F = sum(!is.na(TravelDistance_Mi[TD_Mi_SSHG_q5 <= TravelDistance_Mi & TravelDistance_Mi <= TD_Mi_SSHG_q95]
)
),
TT_Sec_SSHG_Mean = mean(TravelTime_Sec, na.rm = TRUE),
TT_Sec_SSHG_Mean_F = mean(TravelTime_Sec[TT_Sec_SSHG_q5 <= TravelTime_Sec & TravelTime_Sec <= TT_Sec_SSHG_q95],
na.rm = TRUE
),
TT_Sec_SSHG_Med = median(TravelTime_Sec, na.rm = TRUE),
TT_Sec_SSHG_Med_F = median(TravelTime_Sec[TT_Sec_SSHG_q5 <= TravelTime_Sec & TravelTime_Sec <= TT_Sec_SSHG_q95],
na.rm = TRUE
),
TT_Sec_SSHG_Cnt = sum(!is.na(TravelTime_Sec)),
TT_Sec_SSHG_Cnt_F = sum(!is.na(TravelTime_Sec[TT_Sec_SSHG_q5 <= TravelTime_Sec & TravelTime_Sec <= TT_Sec_SSHG_q95]
)
),
TT_Hr_SSHG_Mean = mean(TravelTime_Hr, na.rm = TRUE),
TT_Hr_SSHG_Mean_F = mean(TravelTime_Hr[TT_Hr_SSHG_q5 <= TravelTime_Hr & TravelTime_Hr <= TT_Hr_SSHG_q95],
na.rm = TRUE
),
TT_Hr_SSHG_Med = median(TravelTime_Hr, na.rm = TRUE),
TT_Hr_SSHG_Med_F = median(TravelTime_Hr[TT_Hr_SSHG_q5 <= TravelTime_Hr & TravelTime_Hr <= TT_Hr_SSHG_q95],
na.rm = TRUE
),
TT_Hr_SSHG_Cnt = sum(!is.na(TravelTime_Hr)),
TT_Hr_SSHG_Cnt_F = sum(!is.na(TravelTime_Hr[TT_Hr_SSHG_q5 <= TravelTime_Hr & TravelTime_Hr <= TT_Hr_SSHG_q95]
)
)
) %>%
data.frame()
rm(Stats_StSt)
rm(Quantiles_SSHG_dt)
str(Stats_StSt_HrGrp)
# View(head(Stats_StSt_HrGrp, 50))
Feature engineering.
Creating a BusEventRoute row number, and a RouteAlt_Lag1 indicator for future identification purposes.
# rm(Quantiles_dt)
# rm(Quantiles_SS_dt)
# rm(AllDays_BusDay)
# rm(Quantiles_SSHG_dt)
# rm(Stats_StSt)
# AllDays_BusDayRoute <- group_by(Stats_StSt_HrGrp,
# Bus_ID,
# Event_Time_Date,
# Route
# ) %>%
# mutate(RouteAlt_Lag2 = lag(RouteAlt) # used in future analyses to identify RouteAlt (direction) changes
#
# # Odometer_Distance_Lag1 = lag(Odometer_Distance),
# #
# # # accounting for potential negative distances
# # TravelDistance_Ft = ifelse(Odometer_Distance >= Odometer_Distance_Lag1,
# # Odometer_Distance - Odometer_Distance_Lag1,
# # NA
# # ),
# # TravelDistance_Mi = TravelDistance_Ft / 5280, #5,280 feet in 1 mile
# #
# # # accounting for potential negative times
# # TravelTime_Sec = as.numeric(ifelse(Event_Time >= lag(Departure_Time),
# # Event_Time - lag(Departure_Time),
# # NA
# # )
# # ),
# # TravelTime_Hr = TravelTime_Sec / 3600, # 3,600 seconds in 1 hour
# #
# # # accounting for potential negative or zero travel times
# # SpeedAvg_Mph = ifelse(TravelTime_Hr > 0,
# # TravelDistance_Mi / TravelTime_Hr,
# # NA
# # )
# ) %>%
# data.frame()
#
# rm(Stats_StSt_HrGrp)
# str(AllDays_BusDayRoute)
Feature engineering.
Calculating a variable to know if the RouteAlt changed. Could be useful in helping identifying weirdness in calculated distances and speeds.
# rm(Stats_StSt_HrGrp)
AllDays_DirChange <- Stats_StSt_HrGrp %>% # AllDays_BusDayRoute %>%
mutate(RteChange = ifelse(Route == Route_Lag1,
"Same",
"Change"
),
RteChange2 = factor(ifelse(is.na(RteChange),
"Change",
RteChange
)
),
DirChange = ifelse(RouteAlt == RouteAlt_Lag1,
"Same",
"Change"
),
DirChange2 = factor(ifelse(is.na(DirChange),
"Change",
DirChange
)
)
)
# rm(AllDays_BusDayRoute)
rm(Stats_StSt_HrGrp)
str(AllDays_DirChange)
View(filter(AllDays_DirChange,
between(RowNum_OG, 2570060, 2570080)
) %>%
select(-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
)
)
Re-ordering the variables to ease with comprehension.
AllDays_NewOrder <- select(AllDays_DirChange,
RowNum_OG,
UniqueLatLng,
group,
StartStop_ID,
BusDay_EventNum,
Bus_ID,
Route,
RteChange2,
RouteAlt,
# RouteAlt_Lag1,
DirChange2,
Route_Direction,
Stop_Sequence,
Start_ID,
Start_Desc,
# Stop_ID,
StopID_Clean,
StopID_Indicator,
Stop_Desc,
countryCode,
Stop_State,
Stop_County,
Stop_City,
Stop_Zip,
Event_Type,
Event_Description,
Event_Time_Yr,
Event_Time_Mth,
Event_Time_Date,
Event_Time_Day,
Event_Time_Hr,
Event_Time_HrGroup,
Event_Time_Min,
Event_Time,
Departure_Time,
Dwell_Time,
Dwell_Time2,
Delta_Time,
Latitude,
Longitude,
Heading,
Odometer_Distance,
Odometer_Distance_Lag1,
Odometer_Distance_Mi,
TravelDistance_Ft,
TravelDistance_Mi,
TravelDistance_Mi_Hvrs,
TD_Mi_q2,
TD_Mi_q98,
TD_Mi_SS_q5,
TD_Mi_SS_q95,
TD_Mi_SSHG_q5,
TD_Mi_SSHG_q95,
TD_Mi_Mean,
TD_Mi_Mean_F,
TD_Mi_SS_Mean,
TD_Mi_SS_Mean_F,
TD_Mi_SSHG_Mean,
TD_Mi_SSHG_Mean_F,
TD_Mi_Med,
TD_Mi_Med_F,
TD_Mi_SS_Med,
TD_Mi_SS_Med_F,
TD_Mi_SSHG_Med,
TD_Mi_SSHG_Med_F,
TD_Mi_Cnt,
TD_Mi_Cnt_F,
TD_Mi_SS_Cnt,
TD_Mi_SS_Cnt_F,
TD_Mi_SSHG_Cnt,
TD_Mi_SSHG_Cnt_F,
TravelTime_Sec,
TT_Sec_q2,
TT_Sec_q98,
TT_Sec_SS_q5,
TT_Sec_SS_q95,
TT_Sec_SSHG_q5,
TT_Sec_SSHG_q95,
TT_Sec_Mean,
TT_Sec_Mean_F,
TT_Sec_SS_Mean,
TT_Sec_SS_Mean_F,
TT_Sec_SSHG_Mean,
TT_Sec_SSHG_Mean_F,
TT_Sec_Med,
TT_Sec_Med_F,
TT_Sec_SS_Med,
TT_Sec_SS_Med_F,
TT_Sec_SSHG_Med,
TT_Sec_SSHG_Med_F,
TT_Sec_Cnt,
TT_Sec_Cnt_F,
TT_Sec_SS_Cnt,
TT_Sec_SS_Cnt_F,
TT_Sec_SSHG_Cnt,
TT_Sec_SSHG_Cnt_F,
TravelTime_Hr,
TT_Hr_q2,
TT_Hr_q98,
TT_Hr_SS_q5,
TT_Hr_SS_q95,
TT_Hr_SSHG_q5,
TT_Hr_SSHG_q95,
TT_Hr_Mean,
TT_Hr_Mean_F,
TT_Hr_SS_Mean,
TT_Hr_SS_Mean_F,
TT_Hr_SSHG_Mean,
TT_Hr_SSHG_Mean_F,
TT_Hr_Med,
TT_Hr_Med_F,
TT_Hr_SS_Med,
TT_Hr_SS_Med_F,
TT_Hr_SSHG_Med,
TT_Hr_SSHG_Med_F,
TT_Hr_Cnt,
TT_Hr_Cnt_F,
TT_Hr_SS_Cnt,
TT_Hr_SS_Cnt_F,
TT_Hr_SSHG_Cnt,
TT_Hr_SSHG_Cnt_F,
SpeedAvg_Mph
)
rm(AllDays_DirChange)
str(select(AllDays_NewOrder,
-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
)
)
str(AllDays_NewOrder)
# View(head(AllDays_NewOrder, 500))
# View(tail(AllDays_NewOrder, 500))
Summarizing the data to help spot anomolies.
View(group_by(AllDays_NewOrder,
Stop_City) %>%
summarise(Cnt_Num = n(),
Cnt_Pct = 100*Cnt_Num / (nrow(AllDays_NewOrder)
)
) %>%
arrange(desc(Cnt_Num))
)
summary(AllDays_NewOrder)
Investigation of TravelDistance_Mi.
View(TravDistMi_Pctiles): 99% of TravelDistance_Mi are about 1 mile or less…but some weird TravelDistance_Mi values (e.g., 584 miles traveled) exist.
TravDistMi_Ntile <- as.data.frame(AllDays_NewOrder$TravelDistance_Mi) %>%
mutate(#Pctile = ntile(AllDays_NewOrder$TravelDistance_Mi, 100),
#MinR = min_rank(AllDays_NewOrder$TravelDistance_Mi),
PctR = percent_rank(AllDays_NewOrder$TravelDistance_Mi),
PctR_Round = round(PctR, 2)
)
colnames(TravDistMi_Ntile)[1] <- "TravelDistance_Mi"
# str(TravDistMi_Ntile)
TravDistMi_Ntile_Rows <- nrow(TravDistMi_Ntile)
# View(tail(TravDistMi_Ntile, 500))
TravDistMi_Pctiles <- group_by(TravDistMi_Ntile,
PctR_Round
) %>%
summarise(
MinTravDistMiAtPctile = min(TravelDistance_Mi),
CntsAtPctile = n(),
PctsAtPctile = CntsAtPctile / TravDistMi_Ntile_Rows
) %>%
mutate(CumSumPAtP = cumsum(PctsAtPctile)
)
rm(TravDistMi_Ntile)
rm(TravDistMi_Ntile_Rows)
View(TravDistMi_Pctiles)
TravDistMi_Pctiles
Investigation of TravelDistance_Mi.
Why are some TravelDistance_Mi “NA”? It looks like partially because the records are the first trip of the day (for that bus), so I purposefully set the distance to “NA”. Another reason is due to the odometer recording a value less than the previous odometer recording. In most cases, I have no explanation for this - though I have observed about 67% of all instances where TravelDistance_Mi is NA (other than because it’s the first record of the day) are instances where DirChange2 is “Change”. This is weird and should be asked to WMATA.
# View(head(AllDays_NewOrder, 500))
View(filter(AllDays_NewOrder,
BusDay_EventNum != 1 # When BusDay_EventNum == 1, TravelDistance_Mi is NA by design (don't want to calculate distance based on yesterday's position)
) %>%
group_by(StartStop_ID) %>%
summarise(Cnts = sum(is.na(TravelDistance_Mi)
)
) %>%
arrange(desc(Cnts)
)
)
View(filter(AllDays_NewOrder,
StartStop_ID == "1000245--1000211"
) %>%
select(RowNum_OG,
StartStop_ID,
Event_Time,
Event_Time_HrGroup,
Bus_ID,
TravelDistance_Mi,
TravelDistance_Mi_Hvrs,
TD_Mi_SS_Mean,
TD_Mi_SS_Mean_F,
TD_Mi_SSHG_Mean,
TD_Mi_SSHG_Mean_F,
TD_Mi_SS_Med,
TD_Mi_SS_Med_F,
TD_Mi_SSHG_Med,
TD_Mi_SSHG_Med_F,
TD_Mi_SS_Cnt,
TD_Mi_SS_Cnt_F,
TD_Mi_SSHG_Cnt,
TD_Mi_SSHG_Cnt_F
) %>%
mutate(Ratio_MeanToHvrs = TD_Mi_SS_Mean / TravelDistance_Mi_Hvrs) %>%
arrange(Event_Time)
)
View(filter(AllDays_NewOrder,
is.na(TravelDistance_Mi)
)
)
# These records are NA becuase the record is the first record of the day (the Event_Time_Date)
View(filter(AllDays_NewOrder,
between(RowNum_OG, 326, 346) | # 336
between(RowNum_OG, 591, 611) | # 601
between(RowNum_OG, 845, 865) # 855
)
)
Investigation of TravelDistance_Mi.
These records are NA becuase the current record odometer is less than the previous record odometer. Theoretically, this should NOT happen. Me: it appears that about 67% of all instances where TravelDistance_Mi is NA (other than because it’s th first record of the day) are instances where DirChange2 is “Change”. This is weird and should be asked to WMATA.
View(filter(AllDays_NewOrder,
between(RowNum_OG, 194, 214) | # 204
between(RowNum_OG, 440, 460) | # 450
between(RowNum_OG, 478, 498) | # 488
between(RowNum_OG, 510, 530) # 520
)
)
TestTable <- filter(AllDays_NewOrder,
BusDay_EventNum != 1
) %>%
mutate(TravelDistance_NA = as.factor(ifelse(is.na(TravelDistance_Mi),
"True",
"False"
)
)
) %>%
group_by(DirChange2, TravelDistance_NA) %>%
summarise(TravDistMi_NACnts = n()
)
# TestTable
TestTable_Spread <- as.data.frame(spread(TestTable,
TravelDistance_NA,
TravDistMi_NACnts
)
) %>%
select(False,
True
)
row.names(TestTable_Spread) <- c("Change", "Same")
# str(TestTable_Spread)
# TestTable_Spread
prop.table(as.table(as.matrix(TestTable_Spread)
),
1
)
prop.table(as.table(as.matrix(TestTable_Spread)
),
2
)
Investigation of TravelDistance_Mi.
Let’s look at just the TravelDistance_Mi values that are NOT “NA”.
rm(TestTable, TestTable_Spread)
TravelDistance_Mi_NoNA <- filter(AllDays_NewOrder,
# TravelDistance_Mi != 0 &
!is.na(TravelDistance_Mi)
)
dim(AllDays_NewOrder)
dim(TravelDistance_Mi_NoNA)
nrow(AllDays_NewOrder) - nrow(TravelDistance_Mi_NoNA)
str(TravelDistance_Mi_NoNA)
summary(TravelDistance_Mi_NoNA)
Investigation of TravelDistance_Mi.
Let’s plot just the TravelDistance_Mi values that are NOT “NA”.
TravDistMi_HistDen <- ggplot(select(TravelDistance_Mi_NoNA,
TravelDistance_Mi
),
aes(x = TravelDistance_Mi,
y = ..density..
)
) +
geom_histogram(binwidth = 0.05, fill = "lightblue", colour = "grey60", size = 0.2) +
geom_line(stat = "density", colour = "red") +
coord_cartesian(xlim = c(0, 1.5), ylim = c(0, 4.0)
) +
labs(title = "Variation in Distance Between Stops",
x = "Travel Distance (miles)",
y = "Density"
)
TravDistMi_HistDen
Investigation of TravelDistance_Mi.
Looking at the extremely large TravelDistance_Mi values. Some (aprox 27%) of TravelDistance_Mi values > 1 mile are when the DirChange2 changes…but what about the other ~73%?
rm(TravelDistance_Mi_NoNA)
# examples of weirdly large TravelDistance_Mi
View(filter(AllDays_NewOrder,
TravelDistance_Mi > 1.1587121212 # 1.1587121212 is the 99th percentile
) %>%
arrange(desc(TravelDistance_Mi)
)
)
# Why are these extremes? Airports? Bus collection points?
View(filter(AllDays_NewOrder,
between(RowNum_OG, 494044, 494064) | # 494054
between(RowNum_OG, 494273, 494293) | # 494283
between(RowNum_OG, 494626, 494646) | # 494636
between(RowNum_OG, 1610156, 1610176) | # 1610166
between(RowNum_OG, 2073074, 2073094) # 2073084
)
)
# Before Removing Runs
# View(filter(AllDays_Sorted,
# between(RowNum_OG, 494044, 494064) | # 494054
# between(RowNum_OG, 494273, 494293) | # 494283
# between(RowNum_OG, 494626, 494646) | # 494636
# between(RowNum_OG, 1610156, 1610176) | # 1610166
# between(RowNum_OG, 2073074, 2073094) # 2073084
# )
# )
# After Removing Runs
# View(filter(AllDays_FirstStopID,
# between(RowNum_OG, 494044, 494064) | # 494054
# between(RowNum_OG, 494273, 494293) | # 494283
# between(RowNum_OG, 494626, 494646) | # 494636
# between(RowNum_OG, 1610156, 1610176) | # 1610166
# between(RowNum_OG, 2073074, 2073094) # 2073084
# )
# )
Investigation of TravelDistance_Mi.
Any relation with DirChange2? Doesn’t look as if this is so.
ExtremeTravDist <- filter(AllDays_NewOrder,
!is.na(TravelDistance_Mi)
) %>%
mutate(TravDist_Extreme = ifelse(TravelDistance_Mi > 1.1587121212, # 1.1587121212 is the 99th percentile
"True",
"False"
)
) %>%
group_by(DirChange2, TravDist_Extreme) %>%
summarise(TravDistMI_ExtCnts = n()
)
# ExtremeTravDist
ExtremeTravDist_Spread <- as.data.frame(spread(ExtremeTravDist,
TravDist_Extreme,
TravDistMI_ExtCnts
)
) %>%
select(False,
True
)
row.names(ExtremeTravDist_Spread) <- c("Change", "Same")
# str(ExtremeTravDist_Spread)
# ExtremeTravDist_Spread
prop.table(as.table(as.matrix(ExtremeTravDist_Spread)
),
1
)
prop.table(as.table(as.matrix(ExtremeTravDist_Spread)
),
2
)
Investigation of TravelDistance_Mi.
Looking at specific buses and StartStop_ID.
rm(ExtremeTravDist, ExtremeTravDist_Spread)
View(arrange(group_by(AllDays_NewOrder,
Bus_ID
) %>%
summarise(DistTrav_Mean = mean(TravelDistance_Mi, na.rm = TRUE),
DistTrav_Med = median(TravelDistance_Mi, na.rm = TRUE)
),
desc(DistTrav_Med)
)
)
# example of extremely small TravelDistance_Mi values (looks like the odometer wasn't functioning)
View(filter(AllDays_NewOrder,
Bus_ID == 6111 |
Bus_ID == 7201 |
Bus_ID == 8058
) %>%
arrange(Bus_ID, Event_Time)
)
View(arrange(group_by(AllDays_NewOrder,
StartStop_ID
) %>%
summarise(DistTrav_Mean = mean(TravelDistance_Mi, na.rm = TRUE),
DistTrav_Med = median(TravelDistance_Mi, na.rm = TRUE)
),
desc(DistTrav_Med)
)
)
# example of extremely large TravelDistance_Mi values...no idea why...
View(filter(AllDays_NewOrder,
StartStop_ID == "1003665--12" |
StartStop_ID == "1003665--5001925" |
StartStop_ID == "3001038--3002565"
) %>%
arrange(StartStop_ID, Event_Time)
)
Investigation of TravelDistance_Mi & TravelDistance_Mi_New.
If TravelDisntace_Mi is below the 5th percentile for that StartStop_ID, or if TravelDisntace_Mi is above the 95th percentile for that StartStop_ID, or if TravelDistance_Mi is NA (when the BusDay_EventNum !=1), consider this an outlier. In this case, replace the value with the mean for that StartStop_ID and HourGroup (TD_Mi_SSHG_Mean_F), or if there are not enough values at the HourGroup level, replace it with the mean for that StartStop_ID.
# View(tail(AllDays_NewOrder, 500))
AllDays_NewTravelDist <-
mutate(AllDays_NewOrder,
TravelDistance_Mi_New = ifelse(!is.na(TravelDistance_Mi) &
(TravelDistance_Mi < TD_Mi_SSHG_q5 |
TravelDistance_Mi > TD_Mi_SSHG_q95
) &
TD_Mi_SSHG_Cnt_F >= 20,
TD_Mi_SSHG_Mean_F,
ifelse(!is.na(TravelDistance_Mi) &
(TravelDistance_Mi < TD_Mi_SSHG_q5 |
TravelDistance_Mi > TD_Mi_SSHG_q95
) &
TD_Mi_SSHG_Cnt_F < 20 &
TD_Mi_SS_Cnt_F >= 20,
TD_Mi_SS_Mean_F,
ifelse(!is.na(TravelDistance_Mi) &
(TravelDistance_Mi < TD_Mi_SSHG_q5 |
TravelDistance_Mi > TD_Mi_SSHG_q95
) &
TD_Mi_SS_Cnt_F < 20 &
TD_Mi_SS_Cnt >= 20,
TD_Mi_SS_Mean,
ifelse(is.na(TravelDistance_Mi) &
BusDay_EventNum != 1 &
TravelDistance_Mi_Hvrs != 0,
TravelDistance_Mi_Hvrs,
ifelse(is.na(TravelDistance_Mi) &
BusDay_EventNum != 1 &
TravelDistance_Mi_Hvrs == 0,
TD_Mi_SS_Mean,
TravelDistance_Mi
))))),
TravelDistance_Mi_New_Label =
factor(ifelse(!is.na(TravelDistance_Mi) &
(TravelDistance_Mi < TD_Mi_SSHG_q5 |
TravelDistance_Mi > TD_Mi_SSHG_q95
) &
TD_Mi_SSHG_Cnt_F >= 20,
"TD_Mi_SSHG_Mean_F",
ifelse(!is.na(TravelDistance_Mi) &
(TravelDistance_Mi < TD_Mi_SSHG_q5 |
TravelDistance_Mi > TD_Mi_SSHG_q95
) &
TD_Mi_SSHG_Cnt_F < 20 &
TD_Mi_SS_Cnt_F >= 20,
"TD_Mi_SS_Mean_F",
ifelse(!is.na(TravelDistance_Mi) &
(TravelDistance_Mi < TD_Mi_SSHG_q5 |
TravelDistance_Mi > TD_Mi_SSHG_q95
) &
TD_Mi_SS_Cnt_F < 20 &
TD_Mi_SS_Cnt >= 20,
"TD_Mi_SS_Mean",
ifelse(is.na(TravelDistance_Mi) &
BusDay_EventNum != 1 &
TravelDistance_Mi_Hvrs != 0,
"TravelDistance_Mi_Hvrs",
ifelse(is.na(TravelDistance_Mi) &
BusDay_EventNum != 1 &
TravelDistance_Mi_Hvrs == 0,
"TD_Mi_SS_Mean",
"TravelDistance_Mi"
)))))
),
TravelDistance_Mi_NewHvrs = ifelse(!is.na(TravelDistance_Mi_Hvrs) &
TravelDistance_Mi_Hvrs != 0 &
(TravelDistance_Mi_New < TD_Mi_q2 |
TravelDistance_Mi_New > TD_Mi_q98
),
TravelDistance_Mi_Hvrs,
TravelDistance_Mi_New
),
TravelDistance_Mi_NewHvrs_Label =
factor(ifelse(!is.na(TravelDistance_Mi_Hvrs) &
TravelDistance_Mi_Hvrs != 0 &
(TravelDistance_Mi_New < TD_Mi_q2 |
TravelDistance_Mi_New > TD_Mi_q98
),
"TravelDistance_Mi_Hvrs",
as.character(TravelDistance_Mi_New_Label)
)
),
SpeedAvg_Mph_NewHvrs = TravelDistance_Mi_NewHvrs / TravelTime_Hr
)
str(AllDays_NewTravelDist)
Investigation of TravelDistance_Mi & TravelDistance_Mi_Hvrs & TravelDistance_Mi_New.
Quick summary and then correlation calculation.
rm(AllDays_NewOrder)
# 38 rows meet this criteria anymore -- appears to be the case when both the Lat Long calculations, and the TravelDistance calculations did not function properly.
View(filter(AllDays_NewTravelDist,
is.na(TravelDistance_Mi_New) &
BusDay_EventNum != 1
)
)
View(AllDays_NewTravelDist %>%
arrange(desc(TravelDistance_Mi_New)) %>%
head(500)
)
summary(select(AllDays_NewTravelDist,
TravelDistance_Mi,
TravelDistance_Mi_Hvrs,
TravelDistance_Mi_New,
TravelDistance_Mi_NewHvrs
)
)
summary(select(filter(AllDays_NewTravelDist,
BusDay_EventNum != 1
),
TravelDistance_Mi,
TravelDistance_Mi_Hvrs,
TravelDistance_Mi_New,
TravelDistance_Mi_NewHvrs
)
)
cor(select(AllDays_NewTravelDist,
TravelDistance_Mi,
TravelDistance_Mi_Hvrs,
TravelDistance_Mi_New,
TravelDistance_Mi_NewHvrs
),
use = "pairwise.complete.obs"
)
Investigation of TravelDistance_Mi_NewHvrs_Label & TravelDistance_Mi_NewHvrs_Label.
Show how the labels changed.
group_by(AllDays_NewTravelDist,
TravelDistance_Mi_New_Label,
TravelDistance_Mi_NewHvrs_Label
) %>%
summarise(CntNum = n(),
CntPct = format(CntNum / nrow(AllDays_NewTravelDist),
scientific = 9999
)
) %>%
arrange(desc(CntPct)
)
Investigation of TravelDistance_Mi & TravelDistance_Mi_Hvrs & TravelDistance_Mi_New.
Graphing the two methods of calculating TravelDistance_Mi.
First, let’s get create a function to plot the liner model equation.
lm_eqn <- function(df, y, x){
m <- lm(y ~ x, df)
l <- list(a = format(coef(m)[1], digits = 2),
b = format(abs(coef(m)[2]), digits = 2),
s1 = ifelse(test = coef(m)[2] > 0,
yes = "+",
no = "-"
),
r2 = format(summary(m)$r.squared,
digits = 3
)
)
eq <- substitute(italic(y) == a~~s1~~b %.% italic(x)*","~~italic(r)^2~"="~r2,
l
)
as.character(as.expression(eq)
)
}
Investigation of TravelDistance_Mi & TravelDistance_Mi_NewHvrs.
Scatter plot (using a 10% sample to making plotting time faster and to reduce un-needed data in the “same” splot).
set.seed(123456789)
AllDays_NewTravelDist_10Pct <- filter(AllDays_NewTravelDist,
!is.na(TravelDistance_Mi_NewHvrs) &
!is.na(TravelDistance_Mi)
) %>%
rename(DistMethod = TravelDistance_Mi_NewHvrs_Label) %>%
sample_frac(0.1)
TravDist_MiVsCalc <- ggplot(select(AllDays_NewTravelDist_10Pct,
TravelDistance_Mi_NewHvrs,
TravelDistance_Mi,
DistMethod
),
aes(x = TravelDistance_Mi,
y = TravelDistance_Mi_NewHvrs,
colour = DistMethod
)
) +
scale_colour_manual(values = c("red","blue", "green", "orange", "black")
) +
geom_point(shape = 1, alpha = 0.5) +
scale_shape(solid = FALSE) +
geom_smooth(method = "lm", colour = "blue") +
geom_abline(intercept = 0, slope = 1, colour = "red") +
coord_cartesian(xlim = c(0, 1.5), ylim = c(0, 1.5)
) +
scale_x_continuous(breaks = seq(0, 1.5, 0.25)
) +
scale_y_continuous(breaks = seq(0, 1.5, 0.25)
) +
theme(legend.position = "bottom", #c(0.85, 0.40),
legend.text = element_text(size = 6)
) +
annotate(label = lm_eqn(df = AllDays_NewTravelDist_10Pct,
x = AllDays_NewTravelDist_10Pct$TravelDistance_Mi,
y = AllDays_NewTravelDist_10Pct$TravelDistance_Mi_NewHvrs
),
# x = 62,
# y = 20,
x = 0.70,
y = 0.00,
geom = "text",
size = 3,
colour = "blue",
parse = TRUE
) +
annotate(label = "Reference Line (slope = 1)",
# x = 16,
# y = 30,
x = 0.80,
y = 1.05,
geom = "text",
size = 3,
colour = "red"
) +
labs(title = "TravelDistance_Mi vs. TravelDistance_Mi_NewHvrs",
x = "TravelDistance_Mi",
y = "TravelDistance_Mi_NewHvrs"
)
# +
# geom_jitter()
TravDist_MiVsCalc
Investigation of TravelDistance_Mi & TravelDistance_Mi_Hvrs & TravelDistance_Mi_New.
Graphing test with rbokeh.
TravDist_MiVsCalc_Bokeh <- figure(data = select(AllDays_NewTravelDist_10Pct,
TravelDistance_Mi_NewHvrs,
TravelDistance_Mi,
DistMethod
),
xlim = c(0, 1.5),
ylim = c(0, 1.5),
legend_location = "bottom_right"
) %>%
ly_points(x = TravelDistance_Mi,
y = TravelDistance_Mi_NewHvrs,
color = DistMethod,
hover = c(TravelDistance_Mi_NewHvrs, TravelDistance_Mi, DistMethod)
) %>%
ly_abline(a = 0, b = 1, color = "red")
TravDist_MiVsCalc_Bokeh
Investigation of TravelDistance_Mi_New.
Calculating the minimum TravelDistance_Mi_New value at each percentile.
rm(TravDist_MiVsCalc_Bokeh)
rm(AllDays_NewTravelDist_10Pct)
summary(select(AllDays_NewTravelDist,
TravelDistance_Mi,
TravelDistance_Mi_Hvrs,
TravelDistance_Mi_New,
TravelDistance_Mi_NewHvrs
)
)
summary(select(filter(AllDays_NewTravelDist,
BusDay_EventNum != 1
),
TravelDistance_Mi,
TravelDistance_Mi_Hvrs,
TravelDistance_Mi_New,
TravelDistance_Mi_NewHvrs
)
)
TravDistMiN_Ntile <- as.data.frame(select(AllDays_NewTravelDist,
StartStop_ID,
TravelDistance_Mi_New_Label,
# TravelDistance_Mi_NewHvrs_Label,
TravelDistance_Mi_New
# TravelDistance_Mi_NewHvrs
)
) %>%
mutate(PctR_N = percent_rank(AllDays_NewTravelDist$TravelDistance_Mi_New),
# PctR_H = percent_rank(AllDays_NewTravelDist$TravelDistance_Mi_NewHvrs),
PctR_Round_N = round(PctR_N, 2)
# PctR_Round_H = round(PctR_H, 2)
)
# str(TravDistMiN_Ntile)
# View(head(TravDistMiN_Ntile, 500))
TravDistMiN_Ntile_Rows <- nrow(TravDistMiN_Ntile)
# View(tail(TravDistMiN_Ntile, 500))
TravDistMiN_Pctiles <- group_by(TravDistMiN_Ntile,
PctR_Round_N
) %>%
summarise(
MinTDMiAtPctile_N = min(TravelDistance_Mi_New),
# MinTDMiAtPctile_H = min(TravelDistance_Mi_NewHvrs),
CntsAtPctile_N = sum(!is.na(TravelDistance_Mi_New)),
# CntsAtPctile_H = sum(!is.na(TravelDistance_Mi_NewHvrs)),
PctsAtPctile_N = CntsAtPctile_N / TravDistMiN_Ntile_Rows
# PctsAtPctile_H = CntsAtPctile_H / TravDistMiN_Ntile_Rows
) %>%
mutate(CumSumPAtP_N = cumsum(PctsAtPctile_N)
# CumSumPAtP_H = cumsum(PctsAtPctile_H)
)
# View(TravDistMiN_Pctiles)
Investigation of TravelDistance_Mi_NewHvrs
Calculating the minimum TravelDistance_Mi_NewHvrs value at each percentile.
TravDistMiH_Ntile <- as.data.frame(select(AllDays_NewTravelDist,
StartStop_ID,
# TravelDistance_Mi_New_Label,
TravelDistance_Mi_NewHvrs_Label,
# TravelDistance_Mi_New,
TravelDistance_Mi_NewHvrs
)
) %>%
mutate(# PctR_N = percent_rank(AllDays_NewTravelDist$TravelDistance_Mi_New),
PctR_H = percent_rank(AllDays_NewTravelDist$TravelDistance_Mi_NewHvrs),
# PctR_Round_N = round(PctR_N, 2),
PctR_Round_H = round(PctR_H, 2)
)
# str(TravDistMiH_Ntile)
# View(head(TravDistMiH_Ntile, 500))
TravDistMiH_Ntile_Rows <- nrow(TravDistMiH_Ntile)
# View(tail(TravDistMiH_Ntile, 500))
TravDistMiH_Pctiles <- group_by(TravDistMiH_Ntile,
PctR_Round_H
) %>%
summarise(
# MinTDMiAtPctile_N = min(TravelDistance_Mi_New),
MinTDMiAtPctile_H = min(TravelDistance_Mi_NewHvrs),
# CntsAtPctile_N = sum(!is.na(TravelDistance_Mi_New)),
CntsAtPctile_H = sum(!is.na(TravelDistance_Mi_NewHvrs)),
# PctsAtPctile_N = CntsAtPctile_N / TravDistMiH_Ntile_Rows,
PctsAtPctile_H = CntsAtPctile_H / TravDistMiH_Ntile_Rows
) %>%
mutate(# CumSumPAtP_N = cumsum(PctsAtPctile_N),
CumSumPAtP_H = cumsum(PctsAtPctile_H)
)
# View(TravDistMiH_Pctiles)
Join TravDistMiH_Pctiles, TravDistMiN_Pctiles, and TravDistMi_Pctiles.
~11% of rides are still showing as less than 0.1 miles of TravelDistance_Mi_NewHvrs.
rm(TravDistMiN_Ntile_Rows, TravDistMiH_Ntile_Rows, TravDistMiN_Ntile, TravDistMiH_Ntile)
# View(TravDistMi_Pctiles)
# View(TravDistMiN_Pctiles)
# View(TravDistMiH_Pctiles)
TravDistMi_Pctiles_All <- inner_join(x = TravDistMi_Pctiles,
y = TravDistMiN_Pctiles,
by = c("PctR_Round" = "PctR_Round_N")
) %>%
inner_join(y = TravDistMiH_Pctiles,
by = c("PctR_Round" = "PctR_Round_H")
) %>%
select(PctR_Round,
MinTravDistMiAtPctile,
MinTDMiAtPctile_N,
MinTDMiAtPctile_H,
CntsAtPctile,
CntsAtPctile_N,
CntsAtPctile_H,
PctsAtPctile,
PctsAtPctile_N,
PctsAtPctile_H,
CumSumPAtP,
CumSumPAtP_N,
CumSumPAtP_H
)
# str(TravDistMi_Pctiles_All)
rm(TravDistMi_Pctiles, TravDistMiN_Pctiles,TravDistMiH_Pctiles)
View(TravDistMi_Pctiles_All)
TravDistMi_Pctiles_All
Investigation of TravelDistance_Mi_New.
Why are there still some small or large TravelDistance_Mi_NewHvrs values.
# View(filter(AllDays_NewTravelDist,
# !is.na(TravelDistance_Mi_NewHvrs)
# ) %>%
# select(-TD_Mi_q2,
# -TD_Mi_q98,
# -TD_Mi_SS_q5,
# -TD_Mi_SS_q95,
# -TD_Mi_SSHG_q5,
# -TD_Mi_SSHG_q95,
# -TD_Mi_Mean,
# -TD_Mi_Mean_F,
# -TD_Mi_SS_Mean,
# -TD_Mi_SS_Mean_F,
# -TD_Mi_SSHG_Mean,
# -TD_Mi_SSHG_Mean_F,
# -TD_Mi_Med,
# -TD_Mi_Med_F,
# -TD_Mi_SS_Med,
# -TD_Mi_SS_Med_F,
# -TD_Mi_SSHG_Med,
# -TD_Mi_SSHG_Med_F,
# -TD_Mi_Cnt,
# -TD_Mi_Cnt_F,
# -TD_Mi_SS_Cnt,
# -TD_Mi_SS_Cnt_F,
# -TD_Mi_SSHG_Cnt,
# -TD_Mi_SSHG_Cnt_F,
# -TT_Sec_q2,
# -TT_Sec_q98,
# -TT_Sec_SS_q5,
# -TT_Sec_SS_q95,
# -TT_Sec_SSHG_q5,
# -TT_Sec_SSHG_q95,
# -TT_Sec_Mean,
# -TT_Sec_Mean_F,
# -TT_Sec_SS_Mean,
# -TT_Sec_SS_Mean_F,
# -TT_Sec_SSHG_Mean,
# -TT_Sec_SSHG_Mean_F,
# -TT_Sec_Med,
# -TT_Sec_Med_F,
# -TT_Sec_SS_Med,
# -TT_Sec_SS_Med_F,
# -TT_Sec_SSHG_Med,
# -TT_Sec_SSHG_Med_F,
# -TT_Sec_Cnt,
# -TT_Sec_Cnt_F,
# -TT_Sec_SS_Cnt,
# -TT_Sec_SS_Cnt_F,
# -TT_Sec_SSHG_Cnt,
# -TT_Sec_SSHG_Cnt_F,
# -TT_Hr_q2,
# -TT_Hr_q98,
# -TT_Hr_SS_q5,
# -TT_Hr_SS_q95,
# -TT_Hr_SSHG_q5,
# -TT_Hr_SSHG_q95,
# -TT_Hr_Mean,
# -TT_Hr_Mean_F,
# -TT_Hr_SS_Mean,
# -TT_Hr_SS_Mean_F,
# -TT_Hr_SSHG_Mean,
# -TT_Hr_SSHG_Mean_F,
# -TT_Hr_Med,
# -TT_Hr_Med_F,
# -TT_Hr_SS_Med,
# -TT_Hr_SS_Med_F,
# -TT_Hr_SSHG_Med,
# -TT_Hr_SSHG_Med_F,
# -TT_Hr_Cnt,
# -TT_Hr_Cnt_F,
# -TT_Hr_SS_Cnt,
# -TT_Hr_SS_Cnt_F,
# -TT_Hr_SSHG_Cnt,
# -TT_Hr_SSHG_Cnt_F
# ) %>%
# arrange(TravelDistance_Mi_NewHvrs) %>%
# head(500)
# )
View(filter(AllDays_NewTravelDist,
!is.na(TravelDistance_Mi_NewHvrs)
) %>%
select(-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
) %>%
arrange(TravelDistance_Mi_NewHvrs) %>%
head(500)
)
# examples of the smallest TravelDistance_Mi_NewHvrs values.
View(filter(AllDays_NewTravelDist,
(RowNum_OG >= 1424440 & RowNum_OG <= 1424460) | # 1424450 -- direction change
(RowNum_OG >= 763292 & RowNum_OG <= 763312) | # 763302 -- direction change
(RowNum_OG >= 1679093 & RowNum_OG <= 1679113) | # 1679103 -- direction change
(RowNum_OG >= 2860918 & RowNum_OG <= 2860938) # 2860928 -- looks correct
) %>%
select(-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
)
)
View(filter(AllDays_NewTravelDist,
!is.na(TravelDistance_Mi_NewHvrs)
) %>%
select(-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
) %>%
arrange(desc(TravelDistance_Mi_NewHvrs)
) %>%
head(500)
)
# examples of the largest TravelDistance_Mi_NewHvrs values.
View(filter(AllDays_NewTravelDist,
(RowNum_OG >= 1092000 & RowNum_OG <= 1092050) | # 1092030 -- direction change
(RowNum_OG >= 1609460 & RowNum_OG <= 1609480) | # 1609470 -- direction change
(RowNum_OG >= 508904 & RowNum_OG <= 508924) | # 508914 -- direction change & original StopID was bad
(RowNum_OG >= 2476345 & RowNum_OG <= 2476365) # 2476355 -- direction change
) %>%
select(-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
)
)
Investigation of TravelTime_Hr.
View(TravDistMi_Pctiles): 98% of TravelTime_Hr are between 7 seconds and 464 seconds (~8 minutes).
TravTimeHr_Ntile <- select(AllDays_NewTravelDist,
TravelTime_Hr
) %>%
mutate(# Pctile = ntile(AllDays_NewTravelDist$TravelTime_Hr, 100),
# MinR = min_rank(AllDays_NewTravelDist$TravelTime_Hr),
PctR = percent_rank(AllDays_NewTravelDist$TravelTime_Hr),
PctR_Round = round(PctR, 2)
)
# str(TravTimeHr_Ntile)
TravTimeHr_Ntile_Rows <- nrow(TravTimeHr_Ntile)
# View(tail(TravTimeHr_Ntile, 500))
TravTimeHr_Pctiles <- group_by(TravTimeHr_Ntile,
PctR_Round
) %>%
summarise(
MinTravTimeHrAtPctile = min(TravelTime_Hr),
CntsAtPctile = n(),
PctsAtPctile = CntsAtPctile / TravTimeHr_Ntile_Rows
) %>%
mutate(CumSumPAtP = cumsum(PctsAtPctile),
MinTravTimeSecAtPctile = MinTravTimeHrAtPctile * 3600
)
rm(TravTimeHr_Ntile_Rows)
rm(TravTimeHr_Ntile)
View(TravTimeHr_Pctiles)
TravTimeHr_Pctiles
Investigation of TravelTime_Hr.
Histogram of TravelTime_Sec.
TravTime_Sec_HistDen <- ggplot(filter(select(AllDays_NewTravelDist,
TravelTime_Sec
),
!is.na(TravelTime_Sec)
),
aes(x = TravelTime_Sec,
y = ..density..
)
) +
geom_histogram(binwidth = 5, fill = "lightblue", colour = "grey60", size = 0.2) +
geom_line(stat = "density", colour = "red") +
# stat_bin(binwidth = 5,
# geom = "text",
# size = 2.5,
# vjust = 1.5,
# aes(label = format(..count.., big.mark = ",")
# ),
# ) +
coord_cartesian(xlim = c(0, 180), ylim = c(0, 0.02)
) +
# theme(legend.position="none") +
labs(title = "Variation in Travel Time",
x = "Travel Time (sec)",
y = "Density"
)
TravTime_Sec_HistDen
Investigation of TravelTime_Sec.
TravelTime_Sec values are NA.
summary(AllDays_NewTravelDist$TravelTime_Sec)
View(select(AllDays_NewTravelDist,
-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
) %>%
filter(is.na(TravelTime_Sec) &
BusDay_EventNum != 1 # TravelTime purposefully not calculated here
)
)
# examples of TravelTime_Sec values that are NA. These are NA because the Event_Time & Departure_Time readings are not accurate (i.e., the previous Departure_Time is BEFORE or EQUAL TO the current Event_Time).
View(filter(AllDays_NewTravelDist,
(RowNum_OG >= 90809 & RowNum_OG <= 90829) | # 90819
(RowNum_OG >= 90881 & RowNum_OG <= 90901) | # 90891
(RowNum_OG >= 2597066 & RowNum_OG <= 2597086) | # 2597076
(RowNum_OG >= 2613305 & RowNum_OG <= 2613325) # 2613315
) %>%
select(-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt"))
)
Investigation of TravelTime_Sec.
TravelTime_Sec values are extremely small.
View(select(AllDays_NewTravelDist,
-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
) %>%
filter(!is.na(TravelTime_Sec)
) %>%
arrange(TravelTime_Sec,
desc(SpeedAvg_Mph_NewHvrs)
) %>%
head(500)
)
# examples where TravelTime_Sec is small (1 sec) and SpeedAvg_Mph_NewHvrs is large.
View(select(AllDays_NewTravelDist,
-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
) %>%
filter((RowNum_OG >= 2217353 & RowNum_OG <= 2217373) | # 2217363
(RowNum_OG >= 3090321 & RowNum_OG <= 3090341) | # 3090331
(RowNum_OG >= 80764 & RowNum_OG <= 80784) | # 80774
(RowNum_OG >= 33840 & RowNum_OG <= 33860) # 33850
)
)
Investigation of TravelTime_Sec.
TravelTime_Sec values are extremely large.
View(select(AllDays_NewTravelDist,
-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
) %>%
filter(!is.na(TravelTime_Sec)
) %>%
arrange(desc(TravelTime_Sec),
SpeedAvg_Mph_NewHvrs
) %>%
head(500)
)
# examples where TravelTime_Sec is large and SpeedAvg_Mph_NewHvrs is small.
View(select(AllDays_NewTravelDist,
-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
) %>%
filter((RowNum_OG >= 1007703 & RowNum_OG <= 1007723) | # 1007713
(RowNum_OG >= 2373564 & RowNum_OG <= 2373584) | # 2373574
(RowNum_OG >= 864379 & RowNum_OG <= 864399) | # 864389
(RowNum_OG >= 2570060 & RowNum_OG <= 2570080) # 2570070
)
)
Investigation of TravelTime_Sec.
Are large TravelTime_Sec values related to RouteChanges? Looks likely. When the Bus involves a Route “change”, there is almost twice as likely to be a case of an outlier TravelTime_Sec value (on the high side).
TTLargeRteChng <- select(AllDays_NewTravelDist,
-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
) %>%
mutate(TT_Out = factor(ifelse(TravelTime_Sec > 464, # this is the 99th percentile
"Outlier",
"Normal"
)
)
)
# str(TTLargeRteChng)
TTLargeRteChng_Cnts <- group_by(TTLargeRteChng,
RteChange2,
TT_Out
) %>%
summarise(Cnts = n()
)
TTLargeRteChng_Spread <- as.data.frame(spread(TTLargeRteChng_Cnts,
TT_Out,
Cnts
)
) %>%
select(-RteChange2)
row.names(TTLargeRteChng_Spread) <- c("Change", "Same")
# str(TTLargeRteChng_Spread)
# When the Bus involves a Route "change", there is almost twice as likely to be a case of an outlier TravelTime_Sec value.
TTLargeRteChng_Spread
prop.table(as.table(as.matrix(TTLargeRteChng_Spread)
),
1
)
prop.table(as.table(as.matrix(TTLargeRteChng_Spread)
),
2
)
# rm(TTLargeRteChng, TTLargeRteChng_Spread)
View(filter(TTLargeRteChng,
!is.na(TravelTime_Sec) &
RteChange2 == "Same"
) %>%
arrange(desc(TravelTime_Sec),
SpeedAvg_Mph_NewHvrs
) %>%
head(500)
)
# examples where TravelTime_Sec is large and SpeedAvg_Mph_NewHvrs is small.
View(filter(TTLargeRteChng,
(RowNum_OG >= 2250290 & RowNum_OG <= 2250310) | # 2250300
(RowNum_OG >= 867717 & RowNum_OG <= 867737) | # 867727
(RowNum_OG >= 864379 & RowNum_OG <= 864399) | # 864389
(RowNum_OG >= 808395 & RowNum_OG <= 808415) # 808405
)
)
Investigation of TravelTime_Sec.
If TravelTime_Sec is below the 5th percentile for that StartStop_ID, or if TravelTime_Sec is above the 95th percentile for that StartStop_ID, consider this an outlier. In this case, replace the value with the mean for that StartStop_ID and HourGroup (TT_Sec_SSHG_Mean_F), or if there are not enough values at the HourGroup level, replace it with the mean for that StartStop_ID.
rm(TTLargeRteChng, TTLargeRteChng_Cnts, TTLargeRteChng_Spread)
NewTravTime <- mutate(AllDays_NewTravelDist,
TT_Sec_New = ifelse(!is.na(TravelTime_Sec) &
(TravelTime_Sec < TT_Sec_SSHG_q5 |
TravelTime_Sec > TT_Sec_SSHG_q95
) &
TT_Sec_SSHG_Cnt_F >= 20,
TT_Sec_SSHG_Mean_F,
ifelse(!is.na(TravelTime_Sec) &
(TravelTime_Sec < TT_Sec_SSHG_q5 |
TravelTime_Sec > TT_Sec_SSHG_q95
) &
TT_Sec_SSHG_Cnt_F < 20 &
TT_Sec_SS_Cnt_F >= 20,
TT_Sec_SS_Mean_F,
ifelse(!is.na(TravelTime_Sec) &
(TravelTime_Sec < TT_Sec_SSHG_q5 |
TravelTime_Sec > TT_Sec_SSHG_q95
) &
TT_Sec_SS_Cnt_F < 20 &
TT_Sec_SS_Cnt >= 20,
TT_Sec_SS_Mean,
ifelse(!is.na(TravelTime_Sec) &
(TravelTime_Sec < TT_Sec_SSHG_q5 |
TravelTime_Sec > TT_Sec_SSHG_q95
) &
TT_Sec_SS_Cnt_F < 20 &
TT_Sec_SS_Cnt < 20 &
RteChange2 == "Change",
NA,
TravelTime_Sec
)))),
TT_Sec_New_Label =
factor(ifelse(!is.na(TravelTime_Sec) &
(TravelTime_Sec < TT_Sec_SSHG_q5 |
TravelTime_Sec > TT_Sec_SSHG_q95
) &
TT_Sec_SSHG_Cnt_F >= 20,
"TT_Sec_SSHG_Mean_F",
ifelse(!is.na(TravelTime_Sec) &
(TravelTime_Sec < TT_Sec_SSHG_q5 |
TravelTime_Sec > TT_Sec_SSHG_q95
) &
TT_Sec_SSHG_Cnt_F < 20 &
TT_Sec_SS_Cnt_F >= 20,
"TT_Sec_SS_Mean_F",
ifelse(!is.na(TravelTime_Sec) &
(TravelTime_Sec < TT_Sec_SSHG_q5 |
TravelTime_Sec > TT_Sec_SSHG_q95
) &
TT_Sec_SS_Cnt_F < 20 &
TT_Sec_SS_Cnt >= 20,
"TT_Sec_SS_Mean",
ifelse(!is.na(TravelTime_Sec) &
(TravelTime_Sec < TT_Sec_SSHG_q5 |
TravelTime_Sec > TT_Sec_SSHG_q95
) &
TT_Sec_SS_Cnt_F < 20 &
TT_Sec_SS_Cnt < 20 &
RteChange2 == "Change",
NA,
"TravelTime_Sec"
))))
),
TT_Hr_New = TT_Sec_New / (60 * 60)
)
dim(AllDays_NewTravelDist)
dim(NewTravTime)
rm(AllDays_NewTravelDist)
summary(select(NewTravTime,
-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
)
)
str(select(NewTravTime,
TravelTime_Sec,
TT_Sec_New,
TT_Sec_New_Label,
TT_Hr_New
)
)
summary(select(NewTravTime,
TravelTime_Sec,
TT_Sec_New,
TT_Sec_New_Label,
TT_Hr_New
)
)
Test investigation of just the X2 Route. Box plots for time between bus arrivals (by HourGroup).
View(head(select(NewTravTime,
-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
)
)
)
X2 <- select(NewTravTime,
-matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
) %>%
filter(Route == "X2")
str(X2)
View(head(arrange(X2,
Bus_ID,
Event_Time
),
500
)
)
X2_ByStop <- group_by(X2,
StopID_Clean
) %>%
arrange(StopID_Clean,
Event_Time) %>%
mutate(Event_Time_L1 = lag(Event_Time),
TimeToEvent_Sec = as.numeric(Event_Time - Event_Time_L1),
TimeToEvent_Min = TimeToEvent_Sec / 60
)
View(head(X2_ByStop, 500))
# Count_Values is needed to display the medians on the box plots
Count_Values <- ddply(as.data.frame(X2_ByStop),
.(Event_Time_HrGroup),
summarise,
Value_Counts = median(TimeToEvent_Min, na.rm = TRUE)
)
TimeBtwEvents_X2_BoxPlot <- ggplot(select(as.data.frame(X2_ByStop),
TimeToEvent_Min,
Event_Time_HrGroup
),
aes(factor(Event_Time_HrGroup),
TimeToEvent_Min,
fill = factor(Event_Time_HrGroup)
)
) +
geom_boxplot(outlier.colour="red", notch=TRUE, na.rm = TRUE) +
geom_text(data = Count_Values,
aes(y = Value_Counts,
label = format(round(Value_Counts, digits = 1),
nsmall = 1
)
),
size = 3,
vjust = -0.5
) +
theme(legend.position="none", axis.text.x = element_text(angle=45)) +
coord_cartesian(# xlim = c(0, 180),
ylim = c(0, 120)
) +
labs(title = "How Often an X2 Arrives at a Given Stop",
x = "Hour Group",
y = "Time Between Busses (min)"
)
TimeBtwEvents_X2_BoxPlot
Test investigation of just the X2 Route. Violin plots for time between bus arrivals (by Hour Group).
TimeBtwEvents_X2_ViolinPlot <- ggplot(select(as.data.frame(X2_ByStop),
TimeToEvent_Min,
Event_Time_HrGroup
),
aes(factor(Event_Time_HrGroup),
TimeToEvent_Min,
fill = factor(Event_Time_HrGroup)
)
) +
geom_violin(draw_quantiles = c(0.25, 0.5, 0.75),
trim = TRUE,
scale = "count",
na.rm = TRUE,
show.legend = NA,
inherit.aes = TRUE
) +
geom_text(data = Count_Values,
aes(y = Value_Counts,
label = format(round(Value_Counts, digits = 1),
nsmall = 1
)
),
size = 2.5,
vjust = -0.5
) +
theme(legend.position="none", axis.text.x = element_text(angle=45)) +
coord_cartesian(# xlim = c(0, 180),
ylim = c(0, 80)
) +
labs(title = "How Often an X2 Arrives at a Given Stop",
x = "Hour Group",
y = "Time Between Busses (min)"
)
TimeBtwEvents_X2_ViolinPlot
Test investigation of just the X2 Route. Box plots for time between bus arrivals (by Zip Code).
# Count_Values is needed to display the medians on the box plots
Count_Values_z <- ddply(as.data.frame(X2_ByStop),
.(Stop_Zip),
summarise,
Value_Counts = median(TimeToEvent_Min, na.rm = TRUE)
)
TimeBtwEvents_X2_BoxPlot_z <- ggplot(select(as.data.frame(X2_ByStop),
TimeToEvent_Min,
Stop_Zip
),
aes(factor(Stop_Zip),
TimeToEvent_Min,
fill = factor(Stop_Zip)
)
) +
geom_boxplot(outlier.colour="red", notch=TRUE, na.rm = TRUE) +
geom_text(data = Count_Values_z,
aes(y = Value_Counts,
label = format(round(Value_Counts, digits = 1),
nsmall = 1
)
),
size = 3,
vjust = -0.5
) +
theme(legend.position="none", axis.text.x = element_text(angle=45)) +
coord_cartesian(# xlim = c(0, 180),
ylim = c(0, 100)
) +
labs(title = "How Often an X2 Arrives at a Given Stop",
x = "Zip Code of Destination",
y = "Time Between Busses (min)"
)
TimeBtwEvents_X2_BoxPlot_z
Test investigation of just the X2 Route. Violin plots for time between bus arrivals (by Zip Code).
TimeBtwEvents_X2_ViolinPlot_z <- ggplot(select(as.data.frame(X2_ByStop),
TimeToEvent_Min,
Stop_Zip
),
aes(factor(Stop_Zip),
TimeToEvent_Min,
fill = factor(Stop_Zip)
)
) +
geom_violin(draw_quantiles = c(0.25, 0.5, 0.75),
trim = TRUE,
scale = "count",
na.rm = TRUE,
show.legend = NA,
inherit.aes = TRUE
) +
geom_text(data = Count_Values_z,
aes(y = Value_Counts,
label = format(round(Value_Counts, digits = 1),
nsmall = 1
)
),
size = 2.5,
vjust = -0.5
) +
theme(legend.position="none", axis.text.x = element_text(angle=45)) +
coord_cartesian(# xlim = c(0, 180),
ylim = c(0, 60)
) +
labs(title = "How Often an X2 Arrives at a Given Stop",
x = "Zip Code of Destination",
y = "Time Between Busses (min)"
)
TimeBtwEvents_X2_ViolinPlot_z
Waiting time analyses.
Munging and sampling data to go from time beteen buses to “average” waiting time.
First, get the max and min times of bus stops (each day, and for each route).
RouteMinMax <- group_by(NewTravTime,
Route,
Event_Time_Date
) %>%
summarise(MinTime = min(Event_Time),
MaxTime = max(Event_Time)
)
str(RouteMinMax)
Classes ‘grouped_df’, ‘tbl_df’, ‘tbl’ and 'data.frame': 1329 obs. of 4 variables:
$ Route : chr "10A" "10A" "10A" "10A" ...
$ Event_Time_Date: int 3 4 5 6 7 3 4 5 6 7 ...
$ MinTime : POSIXct, format: "2016-10-03 00:00:19" "2016-10-04 00:00:54" ...
$ MaxTime : POSIXct, format: "2016-10-03 23:57:27" "2016-10-04 23:59:23" ...
- attr(*, "vars")=List of 1
..$ : symbol Route
- attr(*, "drop")= logi TRUE
View(RouteMinMax)
Waiting time analyses.
Munging and sampling data to go from time beteen buses to “average” waiting time.
(Pulls here are done by day, as the data are too large to do at once.)
# Bind all the individual dataframes together.
WaitData_DayPull <- bind_rows(Testing_3,
Testing_4,
Testing_5,
Testing_6,
Testing_7
) %>%
mutate(WaitTime_Sec3 = NB - SampTime,
WaitTime_Min3 = WaitTime_Sec3 / 60
) %>%
arrange(Route,
StopID_Clean,
Event_Time
)
str(WaitData_DayPull)
'data.frame': 2666526 obs. of 23 variables:
$ RowNum_OG : int 771269 510393 842137 416282 403679 478483 842251 403790 842364 403906 ...
$ Route : chr "10A" "10A" "10A" "10A" ...
$ Event_Time_Date : int 3 3 3 3 3 3 3 3 3 3 ...
$ StopID_Clean : chr "2" "2" "2" "2" ...
$ Event_Type : int 3 4 3 3 4 3 3 4 3 4 ...
$ Event_Description : Factor w/ 3 levels "Serviced Stop ",..: 1 3 1 1 3 1 1 3 1 3 ...
$ Event_Time_Yr : int 2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
$ Event_Time_Mth : int 10 10 10 10 10 10 10 10 10 10 ...
$ Event_Time_Day : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 2 2 2 2 2 2 2 2 2 2 ...
$ Event_Time_Hr : int 0 1 5 5 6 6 7 8 9 10 ...
$ Event_Time_HrGroup: Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 1 1 2 2 3 3 3 3 4 4 ...
$ Event_Time_Min : int 1 3 5 38 21 40 12 36 21 27 ...
$ Event_Time : POSIXct, format: "2016-10-03 00:01:53" "2016-10-03 01:03:51" ...
$ MinTime : POSIXct, format: "2016-10-03 00:00:19" "2016-10-03 00:00:19" ...
$ MaxTime : POSIXct, format: "2016-10-03 23:57:27" "2016-10-03 23:57:27" ...
$ SampTime : POSIXct, format: "2016-10-03 15:35:56" "2016-10-03 10:41:52" ...
$ NB : POSIXct, format: "2016-10-03 16:01:44" "2016-10-03 10:42:48" ...
$ WaitTime_Min : num 25.79 55.82 2.44 28.76 1.48 ...
$ WaitTime_Sec : num 1547.1 3349.2 146.6 1725.5 88.9 ...
$ WaitTime_Sec2 : num 25.79 55.82 2.44 28.76 1.48 ...
$ WaitTime_Min2 : num 0.4298 0.9303 0.0407 0.4793 0.0247 ...
$ WaitTime_Sec3 :Class 'difftime' atomic [1:2666526] 1547.1 55.8 8794.3 1725.5 5333.4 ...
.. ..- attr(*, "units")= chr "secs"
$ WaitTime_Min3 :Class 'difftime' atomic [1:2666526] 25.79 0.93 146.57 28.76 88.89 ...
.. ..- attr(*, "units")= chr "secs"
View(head(WaitData_DayPull, 500))
View(tail(WaitData_DayPull, 500))
Waiting time analyses.
Munging and sampling data to go from time beteen buses to “average” waiting time.
Basic investigation of any missing rows from data pulled by day.
DistinctRowNum_OG <- distinct(select(WaitData_DayPull,
RowNum_OG
)
)
str(DistinctRowNum_OG)
View(
anti_join(Samp,
DistinctRowNum_OG,
by = c("RowNum_OG" = "RowNum_OG")
)
)
# The samp time is AFTER the last bus passed that StopID_Clean
View(filter(Samp,
Event_Time > "2016-10-07 19:48:41" &
Route == "X2" &
StopID_Clean == 1003774
)
)
# Next Bus (NB) can be on the next morning
View(filter(Testing7,
SampTime > "2016-10-06 23:58:00" &
SampTime < "2016-10-06 23:59:59")
)
Waiting time analyses.
Munging and sampling data to go from time beteen buses to “average” waiting time.
(Pulls here are done by groupings of bus routes, as the data are too large to do at once.)
First, we need to find the most common bus routes.
rm(DistinctRowNum_OG)
object 'DistinctRowNum_OG' not found
# View(head(NewTravTime, 500))
set.seed(123456789)
BusGroups <- group_by(NewTravTime,
Route
) %>%
summarise(Cnt_Num = n(),
Cnt_Pct = Cnt_Num / nrow(NewTravTime)
) %>%
arrange(desc(Cnt_Num)
) %>%
mutate(RowNum = row_number(),
RandNum = runif(n = 268),
RouteGroup = ifelse(RandNum <= 0.2,
1,
ifelse(RandNum <= 0.4,
2,
ifelse(RandNum <= 0.6,
3,
ifelse(RandNum <= 0.8,
4,
5
))))
)
str(BusGroups)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 268 obs. of 6 variables:
$ Route : chr "70" "W4" "B2" "S2" ...
$ Cnt_Num : int 48269 47672 43173 42934 41462 38968 38566 37761 37718 36524 ...
$ Cnt_Pct : num 0.0172 0.017 0.0154 0.0153 0.0148 ...
$ RowNum : int 1 2 3 4 5 6 7 8 9 10 ...
$ RandNum : num 0.693 0.673 0.654 0.719 0.922 ...
$ RouteGroup: num 4 4 4 4 5 5 2 5 2 3 ...
View(BusGroups)
summary(BusGroups)
Route Cnt_Num Cnt_Pct RowNum
Length:268 Min. : 4 Min. :1.424e-06 Min. : 1.00
Class :character 1st Qu.: 2640 1st Qu.:9.396e-04 1st Qu.: 67.75
Mode :character Median : 7358 Median :2.619e-03 Median :134.50
Mean :10483 Mean :3.731e-03 Mean :134.50
3rd Qu.:17014 3rd Qu.:6.056e-03 3rd Qu.:201.25
Max. :48269 Max. :1.718e-02 Max. :268.00
RandNum RouteGroup
Min. :0.001084 Min. :1.000
1st Qu.:0.255701 1st Qu.:2.000
Median :0.512479 Median :3.000
Mean :0.501473 Mean :3.022
3rd Qu.:0.756575 3rd Qu.:4.000
Max. :0.997351 Max. :5.000
Waiting time analyses.
Munging and sampling data to go from time beteen buses to “average” waiting time.
(Pulls here are done by groupings of bus routes, as the data are too large to do at once.)
str(WaitData_RoutePull)
'data.frame': 2780848 obs. of 22 variables:
$ RowNum_OG : int 771269 510393 842137 416282 403679 478483 842251 403790 842364 403906 ...
$ Route : chr "10A" "10A" "10A" "10A" ...
$ RouteGroup : num 4 4 4 4 4 4 4 4 4 4 ...
$ Event_Time_Date : int 3 3 3 3 3 3 3 3 3 3 ...
$ StopID_Clean : chr "2" "2" "2" "2" ...
$ Event_Type : int 3 4 3 3 4 3 3 4 3 4 ...
$ Event_Description : Factor w/ 3 levels "Serviced Stop ",..: 1 3 1 1 3 1 1 3 1 3 ...
$ Event_Time_Yr : int 2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
$ Event_Time_Mth : int 10 10 10 10 10 10 10 10 10 10 ...
$ Event_Time_Day : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 2 2 2 2 2 2 2 2 2 2 ...
$ Event_Time_Hr : int 0 1 5 5 6 6 7 8 9 10 ...
$ Event_Time_HrGroup: Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 1 1 2 2 3 3 3 3 4 4 ...
$ Event_Time_Min : int 1 3 5 38 21 40 12 36 21 27 ...
$ Event_Time : POSIXct, format: "2016-10-03 00:01:53" "2016-10-03 01:03:51" ...
$ MinTime : POSIXct, format: "2016-10-03 00:00:19" "2016-10-03 00:00:19" ...
$ MaxTime : POSIXct, format: "2016-10-03 23:57:27" "2016-10-03 23:57:27" ...
$ SampTime : POSIXct, format: "2016-10-03 08:00:38" "2016-10-03 02:41:02" ...
$ NB : POSIXct, format: "2016-10-03 08:36:07" "2016-10-03 05:05:41" ...
$ WaitTime_Min : num 35.47 2.41 22.98 4.94 7.99 ...
$ WaitTime_Sec : num 2128 145 1379 296 480 ...
$ WaitTime_Sec2 :Class 'difftime' atomic [1:2780848] 2128 8679 1379 296 480 ...
.. ..- attr(*, "units")= chr "secs"
$ WaitTime_Min2 :Class 'difftime' atomic [1:2780848] 35.47 144.65 22.98 4.94 7.99 ...
.. ..- attr(*, "units")= chr "secs"
Waiting time analyses.
Munging and sampling data to go from time beteen buses to “average” waiting time.
Compare WaitData pulled by day and pulled by route.
WaitData_Diff <- anti_join(WaitData_RoutePull,
WaitData_DayPull,
by = c("RowNum_OG" = "RowNum_OG"
)
) %>%
select(-WaitTime_Min,
-WaitTime_Sec
)
str(WaitData_Diff)
'data.frame': 130807 obs. of 20 variables:
$ RowNum_OG : int 2902760 2952760 2637547 1771590 2911289 1129658 1780069 1729217 1273777 2950017 ...
$ Route : chr "Z8" "Z8" "Z8" "Z8" ...
$ RouteGroup : num 1 1 1 1 1 1 1 1 1 1 ...
$ Event_Time_Date : int 7 7 6 5 7 6 6 6 3 7 ...
$ StopID_Clean : chr "2005465" "2005465" "2005465" "2005465" ...
$ Event_Type : int 3 3 4 3 3 4 3 4 4 3 ...
$ Event_Description : Factor w/ 3 levels "Serviced Stop ",..: 1 1 3 1 1 3 1 3 3 1 ...
$ Event_Time_Yr : int 2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
$ Event_Time_Mth : int 10 10 10 10 10 10 10 10 10 10 ...
$ Event_Time_Day : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 6 6 5 4 6 5 5 5 2 6 ...
$ Event_Time_Hr : int 19 10 15 17 17 21 17 8 8 18 ...
$ Event_Time_HrGroup: Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 7 4 6 6 6 8 6 3 3 7 ...
$ Event_Time_Min : int 51 18 49 55 40 8 7 17 10 7 ...
$ Event_Time : POSIXct, format: "2016-10-07 19:51:47" "2016-10-07 10:18:57" ...
$ MinTime : POSIXct, format: "2016-10-07 00:00:07" "2016-10-07 00:00:07" ...
$ MaxTime : POSIXct, format: "2016-10-07 23:59:55" "2016-10-07 23:59:55" ...
$ SampTime : POSIXct, format: "2016-10-07 04:55:14" "2016-10-07 21:41:22" ...
$ NB : POSIXct, format: "2016-10-07 05:12:42" "2016-10-07 21:45:51" ...
$ WaitTime_Sec2 :Class 'difftime' atomic [1:130807] 1048 269 10822 465 1354 ...
.. ..- attr(*, "units")= chr "secs"
$ WaitTime_Min2 :Class 'difftime' atomic [1:130807] 17.46 4.48 180.36 7.75 22.56 ...
.. ..- attr(*, "units")= chr "secs"
View(head(WaitData_Diff, 500))
Waiting time analyses.
Munging and sampling data to go from time beteen buses to “average” waiting time.
Compare WaitData (pulled by route) and original data (NewTravTime).
filter(Samp,
Route == "X2" &
StopID_Clean == 1003774
# RowNum_OG = 1146723
# Event_Time = 2016-10-07 15:32:18
)
Error in filter_(.data, .dots = lazyeval::lazy_dots(...)) :
object 'Samp' not found
Clean up the data a bit.
rm(Compare_NTT_WD)
str(WaitTime_AsNum)
'data.frame': 2810109 obs. of 64 variables:
$ RowNum_OG : int 771269 510393 842137 416282 403679 478483 842251 403790 842364 403906 ...
$ UniqueLatLng : chr "38.867313__-77.053574" "38.867313__-77.053574" "38.867313__-77.053574" "38.867313__-77.053574" ...
$ group : Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
$ StartStop_ID : chr "6000273--2" "6000273--2" "6000273--2" "6000273--2" ...
$ BusDay_EventNum : int 2 70 55 55 55 94 164 158 272 266 ...
$ Bus_ID : int 2915 2719 2950 2634 2625 2674 2950 2625 2950 2625 ...
$ Route : chr "10A" "10A" "10A" "10A" ...
$ RteChange2 : Factor w/ 2 levels "Change","Same": 2 2 2 2 2 2 2 2 2 2 ...
$ RouteAlt : Factor w/ 14 levels "1","10","11",..: 6 6 6 6 6 6 6 6 6 6 ...
$ DirChange2 : Factor w/ 2 levels "Change","Same": 2 2 2 2 2 2 2 2 2 2 ...
$ Route_Direction : Factor w/ 12 levels "","ANTICLKW",..: 7 7 7 7 7 7 7 7 7 7 ...
$ Stop_Sequence : int 55 55 55 55 55 55 55 55 55 55 ...
$ Start_ID : chr "6000273" "6000273" "6000273" "6000273" ...
$ Start_Desc : chr "ARMY-NAVY DR + S HAYES ST" "ARMY-NAVY DR + S HAYES ST" "ARMY-NAVY DR + S HAYES ST" "ARMY-NAVY DR + S HAYES ST" ...
$ StopID_Clean : chr "2" "2" "2" "2" ...
$ StopID_Indicator : Factor w/ 2 levels "ID_Bad","ID_OK": 1 1 1 1 1 1 1 1 1 1 ...
$ Stop_Desc : chr "PENTAGON INBOUND STOP" "PENTAGON INBOUND STOP" "PENTAGON INBOUND STOP" "PENTAGON INBOUND STOP" ...
$ countryCode : Factor w/ 1 level "US": 1 1 1 1 1 1 1 1 1 1 ...
$ Stop_State : Factor w/ 3 levels "DC","MD","VA": 3 3 3 3 3 3 3 3 3 3 ...
$ Stop_County : Factor w/ 11 levels "Anne Arundel",..: 2 2 2 2 2 2 2 2 2 2 ...
$ Stop_City : Factor w/ 56 levels "Accokeek","Alexandria",..: 4 4 4 4 4 4 4 4 4 4 ...
$ Stop_Zip : Factor w/ 153 levels "20001","20002",..: 132 132 132 132 132 132 132 132 132 132 ...
$ Event_Type : int 3 4 3 3 4 3 3 4 3 4 ...
$ Event_Description : Factor w/ 3 levels "Serviced Stop ",..: 1 3 1 1 3 1 1 3 1 3 ...
$ Event_Time_Yr : int 2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
$ Event_Time_Mth : int 10 10 10 10 10 10 10 10 10 10 ...
$ Event_Time_Date : int 3 3 3 3 3 3 3 3 3 3 ...
$ Event_Time_Day : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 2 2 2 2 2 2 2 2 2 2 ...
$ Event_Time_Hr : int 0 1 5 5 6 6 7 8 9 10 ...
$ Event_Time_HrGroup : Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 1 1 2 2 3 3 3 3 4 4 ...
$ Event_Time_Min : int 1 3 5 38 21 40 12 36 21 27 ...
$ Event_Time : POSIXct, format: "2016-10-03 00:01:53" "2016-10-03 01:03:51" ...
$ Departure_Time : POSIXct, format: "2016-10-03 00:01:53" "2016-10-03 01:03:51" ...
$ Dwell_Time : int 0 0 0 0 0 0 0 0 0 0 ...
$ Dwell_Time2 : num 0 0 0 0 0 0 0 0 0 0 ...
$ Delta_Time : int -210 -89 -35 149 914 253 217 1267 400 900 ...
$ Latitude : num 38.9 38.9 38.9 38.9 38.9 ...
$ Longitude : num -77.1 -77.1 -77.1 -77.1 -77.1 ...
$ Heading : int 23 23 23 23 23 23 23 23 23 23 ...
$ Odometer_Distance : int 1131407 909311 87585 80914 88439 69784 211146 212739 336615 337781 ...
$ Odometer_Distance_Lag1 : int 1131407 908412 87585 80914 85325 69784 211146 211995 336615 337065 ...
$ Odometer_Distance_Mi : num 214.3 172.2 16.6 15.3 16.7 ...
$ TravelDistance_Ft : int NA 899 NA NA 3114 NA NA 744 NA 716 ...
$ TravelDistance_Mi : num NA 0.17 NA NA 0.59 ...
$ TravelDistance_Mi_Hvrs : num 0.322 0.322 0.322 0.322 0.319 ...
$ TravelTime_Sec : num 94 191 130 85 183 114 183 183 124 128 ...
$ TravelTime_Hr : num 0.0261 0.0531 0.0361 0.0236 0.0508 ...
$ SpeedAvg_Mph : num NA 3.21 NA NA 11.6 ...
$ TravelDistance_Mi_New : num 0.322 0.17 0.322 0.322 0.59 ...
$ TravelDistance_Mi_New_Label : Factor w/ 5 levels "TD_Mi_SS_Mean",..: 5 4 5 5 4 5 5 4 5 4 ...
$ TravelDistance_Mi_NewHvrs : num 0.322 0.17 0.322 0.322 0.59 ...
$ TravelDistance_Mi_NewHvrs_Label: Factor w/ 5 levels "TD_Mi_SS_Mean",..: 5 4 5 5 4 5 5 4 5 4 ...
$ SpeedAvg_Mph_NewHvrs : num 12.32 3.21 8.91 13.62 11.6 ...
$ TT_Sec_New : num 94 191 130 85 183 114 183 183 124 128 ...
$ TT_Sec_New_Label : Factor w/ 4 levels "TravelTime_Sec",..: 1 1 1 1 1 1 1 1 1 1 ...
$ TT_Hr_New : num 0.0261 0.0531 0.0361 0.0236 0.0508 ...
$ RouteGroup : num 4 4 4 4 4 4 4 4 4 4 ...
$ MinTime : POSIXct, format: "2016-10-03 00:00:19" "2016-10-03 00:00:19" ...
$ MaxTime : POSIXct, format: "2016-10-03 23:57:27" "2016-10-03 23:57:27" ...
$ SampTime : POSIXct, format: "2016-10-03 08:00:38" "2016-10-03 02:41:02" ...
$ NB : POSIXct, format: "2016-10-03 08:36:07" "2016-10-03 05:05:41" ...
$ WaitTime_Sec2 : num 2128 8679 1379 296 480 ...
$ WaitTime_Min2 : num 35.47 144.65 22.98 4.94 7.99 ...
$ RouteStop_ID : Factor w/ 20897 levels "10A__2","10A__3",..: 1 1 1 1 1 1 1 1 1 1 ...
General exploration of wait times.
filter(WaitTime_AsNum,
Route == "D8" & # route has VERY limited service after midnight
StopID_Clean == 1001669
# Event_Time = 2016-10-06 20:31:16
)
Error in filter_(.data, .dots = lazyeval::lazy_dots(...)) :
object 'WaitTime_AsNum' not found
Looks like there might be an issue in wait times when very few Route-Stop combinations are included in the dataset. Let’s explore these.
Histogram of the counts of Route-StopID combinations.
RouteStop_Cnts_Bar <- ggplot(RouteStop_CntOfCnt,
aes(x = RouteStop_CntNum,
# y = ..density..
y = RouteStopCnt_CntNum
)
) +
# geom_histogram(binwidth = 5, fill = "lightblue", colour = "grey60", size = 0.2) +
geom_col(fill = "lightblue", colour = "grey60", size = 0.2) +
coord_cartesian(xlim = c(0, 500)
# ylim = c(0, 0.02)
) +
labs(title = "Variation in Routes Passing a Specific Stop",
x = "Occurrences of Route-StopID Combiantions",
y = "Counts"
)
RouteStop_Cnts_Bar

Create a new dataset limiting extremely small counts of Route-StopID combinations.
filter(WaitTime_RteCnts,
RouteStop_CntNum > 60 # 12 passes per day in a 5-day dataset
) %>%
select(WaitTime_Min2) %>%
summary()
WaitTime_Min2
Min. : 0.000
1st Qu.: 7.477
Median : 16.512
Mean : 49.070
3rd Qu.: 33.572
Max. :2478.582
NA's :16298
filter(WaitTime_RteCnts,
WaitTime_Min2 < 180 # probably means that something went wrong
) %>%
select(WaitTime_Min2) %>%
summary()
WaitTime_Min2
Min. : 0.000
1st Qu.: 6.969
Median : 15.156
Mean : 25.022
3rd Qu.: 28.187
Max. :180.000
Histogram of all wait times.
WaitTime_AllBus_HistDen <- ggplot(filter(select(WaitTime_RteCnts,
WaitTime_Min2
),
!is.na(WaitTime_Min2)
),
aes(x = WaitTime_Min2,
y = ..density..
)
) +
geom_histogram(binwidth = 5, fill = "lightblue", colour = "grey60", size = 0.2) +
geom_line(stat = "density", colour = "red") +
scale_x_continuous(breaks = seq(0, 300, 30)
) +
coord_cartesian(xlim = c(0, 300),
ylim = c(0, 0.035)
) +
labs(title = "Variation in Wait Time",
x = "Wait Time (min)",
y = "Density"
)
WaitTime_AllBus_HistDen

Box plots for WaitTime (all busses, by Zip Code).
# Count_Values is needed to display the medians on the box plots
BusRoute <- select(WaitTime_RteCnts,
Route,
WaitTime_Min2,
Stop_Zip
) %>%
filter(Route == "X2")
CountValues_AllBus_Zip <- ddply(BusRoute,
.(Stop_Zip),
summarise,
Value_Counts = median(WaitTime_Min2, na.rm = TRUE)
)
WaitTime_AllBus_Zip_Box <- ggplot(BusRoute,
aes(factor(Stop_Zip),
WaitTime_Min2,
fill = factor(Stop_Zip)
)
) +
geom_boxplot(outlier.colour="red", notch=TRUE, na.rm = TRUE) +
geom_text(data = CountValues_AllBus_Zip,
aes(y = Value_Counts,
label = format(round(Value_Counts, digits = 1),
nsmall = 1
)
),
size = 3,
vjust = -0.5
) +
theme(legend.position="none", axis.text.x = element_text(angle=45)) +
coord_cartesian(# xlim = c(0, 180),
ylim = c(0, 45)
) +
labs(title = "Waiting Time at a Given Stop (for the X2)",
x = "Zip Code of Destination",
y = "Waiting Time (min)"
)
WaitTime_AllBus_Zip_Box

Test investigation of just the X2 Route. Violin plots for time between bus arrivals (by Zip Code).
WaitTime_AllBus_Zip_Violin <- ggplot(BusRoute,
aes(factor(Stop_Zip),
WaitTime_Min2,
fill = factor(Stop_Zip)
)
) +
geom_violin(draw_quantiles = c(0.25, 0.5, 0.75),
trim = TRUE,
scale = "count",
na.rm = TRUE,
show.legend = NA,
inherit.aes = TRUE
) +
geom_text(data = CountValues_AllBus_Zip,
aes(y = Value_Counts,
label = format(round(Value_Counts, digits = 1),
nsmall = 1
)
),
size = 3.5,
vjust = -0.5
) +
theme(legend.position="none", axis.text.x = element_text(angle=45)) +
coord_cartesian(# xlim = c(0, 180),
ylim = c(0, 45)
) +
labs(title = "Waiting Time at a Given Stop (for the X2)",
x = "Zip Code of Destination",
y = "Waiting Time (min)"
)
TimeBtwEvents_X2_ViolinPlot_z

Box plots for WaitTime (Zip Code, by HourGroupZip).
# Count_Values is needed to display the medians on the box plots
Zip <- select(WaitTime_RteCnts,
Route,
WaitTime_Min2,
Stop_Zip,
Event_Time_HrGroup
) %>%
filter(Stop_Zip == 20002)
CountValues_AllBus_HG <- ddply(Zip,
.(Event_Time_HrGroup),
summarise,
Value_Counts = median(WaitTime_Min2,
na.rm = TRUE
)
)
WaitTime_AllBus_HG_Box <- ggplot(Zip,
aes(factor(Event_Time_HrGroup),
WaitTime_Min2,
fill = factor(Event_Time_HrGroup)
)
) +
geom_boxplot(outlier.colour="red", notch=TRUE, na.rm = TRUE) +
geom_text(data = CountValues_AllBus_HG,
aes(y = Value_Counts,
label = format(round(Value_Counts, digits = 1),
nsmall = 1
)
),
size = 2.5,
vjust = -0.5
) +
theme(legend.position="none", axis.text.x = element_text(angle=45)) +
coord_cartesian(# xlim = c(0, 180),
ylim = c(0, 45)
) +
labs(title = "Waiting Time at a Given Stop (for Zip 20002)",
x = "Hour Group",
y = "Waiting Time (min)"
)
# facet_wrap(~Stop_Zip
# # nrow = 5
# )
WaitTime_AllBus_HG_Box

Violin plots for WaitTime (Zip Code, by HourGroupZip).
WaitTime_AllBus_HG_Vln <- ggplot(Zip,
aes(factor(Event_Time_HrGroup),
WaitTime_Min2,
fill = factor(Event_Time_HrGroup)
)
) +
geom_violin(draw_quantiles = c(0.25, 0.5, 0.75),
trim = TRUE,
scale = "count",
na.rm = TRUE,
show.legend = NA,
inherit.aes = TRUE
) +
geom_text(data = CountValues_AllBus_HG,
aes(y = Value_Counts,
label = format(round(Value_Counts, digits = 1),
nsmall = 1
)
),
size = 2.5,
vjust = -0.5
) +
theme(legend.position="none", axis.text.x = element_text(angle=45)) +
coord_cartesian(# xlim = c(0, 180),
ylim = c(0, 90)
) +
labs(title = "Waiting Time at a Given Stop (for Zip 20002)",
x = "Hour Group",
y = "Waiting Time (min)"
)
# facet_wrap(~Stop_Zip
# # nrow = 5
# )
WaitTime_AllBus_HG_Vln

Box plots for WaitTime (Route, by HourGroupZip).
Violin plots for WaitTime (Zip Code, by HourGroupZip).

X2 Percentiles Line Graph Test.

GET DATA READY FOR SHINY
Shiny_WaitData_Base <- select(WaitTime_RteCnts,
Route,
Stop_Zip,
Event_Time_Date,
Event_Time_Day,
Event_Time_HrGroup,
Event_Time_Hr,
Latitude,
Longitude,
WaitTime_Min2
)
Shiny_WaitData_Base$Route <- factor(Shiny_WaitData_Base$Route)
str(Shiny_WaitData_Base)
'data.frame': 2810109 obs. of 9 variables:
$ Route : Factor w/ 268 levels "10A","10B","10E",..: 1 1 1 1 1 1 1 1 1 1 ...
$ Stop_Zip : Factor w/ 153 levels "20001","20002",..: 132 132 132 132 132 132 132 132 132 132 ...
$ Event_Time_Date : int 3 3 3 3 3 3 3 3 3 3 ...
$ Event_Time_Day : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tues"<..: 2 2 2 2 2 2 2 2 2 2 ...
$ Event_Time_HrGroup: Ord.factor w/ 8 levels "Group0_2"<"Group3_5"<..: 1 1 2 2 3 3 3 3 4 4 ...
$ Event_Time_Hr : int 0 1 5 5 6 6 7 8 9 10 ...
$ Latitude : num 38.9 38.9 38.9 38.9 38.9 ...
$ Longitude : num -77.1 -77.1 -77.1 -77.1 -77.1 ...
$ WaitTime_Min2 : num 35.47 144.65 22.98 4.94 7.99 ...
write.table(Shiny_WaitData_Base,
"Shiny_WaitData_Base.txt",
quote = FALSE,
sep = "\t",
row.names = FALSE
)
Testing mapping functionaltiy
map <- get_map(location = c(lon = -77.03676, lat = 38.89784),
source = "google",
# maptype = "roadmap"
zoom = 12
)
Source : https://maps.googleapis.com/maps/api/staticmap?center=38.89784,-77.03676&zoom=12&size=640x640&scale=2&maptype=terrain&language=en-EN
ggmap(map) +
geom_polygon(aes(x = long, y = lat, group = group),
data = ggtract,
colour = 'white',
fill = 'black',
alpha = .4,
size = .3
)

NA
Investigating TravelTime_Sec.
View(filter(TTLargeRteChng,
!is.na(TravelTime_Sec) &
RteChange2 == "Same"
) %>%
arrange(desc(TravelTime_Sec),
SpeedAvg_Mph_NewHvrs
) %>%
head(500)
)
# examples where TravelTime_Sec is small (1 sec) and SpeedAvg_Mph_NewHvrs is large.
View(select(NewTravTime,
# -matches("(q(2|5|(95)|(98)))|Mean|Med|Cnt")
-(TD_Mi_q2:TD_Mi_SSHG_Cnt_F),
-(TT_Hr_q2:TT_Hr_SSHG_Cnt_F)
) %>%
filter((RowNum_OG >= 2217353 & RowNum_OG <= 2217373) | # 2217363
(RowNum_OG >= 3090321 & RowNum_OG <= 3090341) | # 3090331
(RowNum_OG >= 80764 & RowNum_OG <= 80784) | # 80774
(RowNum_OG >= 33840 & RowNum_OG <= 33860) # 33850
)
)
# examples where TravelTime_Sec is large and SpeedAvg_Mph_NewHvrs is small.
View(filter(TTLargeRteChng,
(RowNum_OG >= 2250290 & RowNum_OG <= 2250310) | # 2250300
(RowNum_OG >= 867717 & RowNum_OG <= 867737) | # 867727
(RowNum_OG >= 864379 & RowNum_OG <= 864399) | # 864389
(RowNum_OG >= 808395 & RowNum_OG <= 808415) # 808405
)
)
# examples where TravelTime_Sec is unusually small (with TravelDistance_Mi values that are large).
View(filter(AllDays_NewTravelDist,
(RowNum_OG >= 1042228 & RowNum_OG <= 1042248) | # 1042238
(RowNum_OG >= 53816 & RowNum_OG <= 53836) | # 53826
(RowNum_OG >= 360571 & RowNum_OG <= 360591) | # 360581
(RowNum_OG >= 502271 & RowNum_OG <= 502291) # 502281 (can't explian the weird TravelTime_Sec calculation here - it's not even an integer!)
)
)
# still trying to explain 502281...on the day of this weirdness, the bus was only in circulation for 4-5 stops (~20 minutes) on that day (Oct 6)
View(filter(AllDays_NewTravelDist,
Bus_ID == 2711
)
)
# exploring large values for TravelTime_Sec
View(filter(AllDays_NewTravelDist,
TravelTime_Sec == 300
) %>%
arrange(desc(TravelTime_Sec),
SpeedAvg_Mph2
)
)
# examples where TravelTime_Sec is unusually large (with TravelDistance_Mi values that are small, so SpeedAvg_Mph values are very small).
View(filter(AllDays_NewTravelDist,
(RowNum_OG >= 2627459 & RowNum_OG <= 2627479) | # 2627469
(RowNum_OG >= 2193344 & RowNum_OG <= 2193364) | # 2193354
(RowNum_OG >= 1644123 & RowNum_OG <= 1644143) | # 1644133
(RowNum_OG >= 869600 & RowNum_OG <= 869620) # 869610
)
)
Investigation of SpeedAvg_Mph2
View(Speed_Pctiles): 90% of SpeedAvg_Mph2 are between ~3mph and ~66mph.
Speed_Ntile <- as.data.frame(AllDays_NewTravelDist$SpeedAvg_Mph2) %>%
mutate(Pctile = ntile(AllDays_NewTravelDist$SpeedAvg_Mph2, 100),
MinR = min_rank(AllDays_NewTravelDist$SpeedAvg_Mph2),
PctR = percent_rank(AllDays_NewTravelDist$SpeedAvg_Mph2),
PctR_Round = round(PctR, 2)
)
colnames(Speed_Ntile)[1] <- "SpeedAvg_Mph2"
str(Speed_Ntile)
Speed_Ntile_Rows <- nrow(Speed_Ntile)
View(tail(Speed_Ntile, 500))
Speed_Pctiles <- group_by(Speed_Ntile,
PctR_Round
) %>%
summarise(
MinSpeedAtPctile = min(SpeedAvg_Mph2),
CntsAtPctile = n(),
PctsAtPctile = CntsAtPctile / Speed_Ntile_Rows
) %>%
mutate(CumSumPAtP = cumsum(PctsAtPctile)
)
View(Speed_Pctiles)
Investigation of SpeedAvg_Mph2.
Exploring the removal of outlier TravelTime_Sec and TravelDistance_Mi.
summary(select(AllDays_NewTravelDist,
SpeedAvg_Mph,
SpeedAvg_Mph2
)
)
summary(select(filter(AllDays_NewTravelDist,
TravelDistance_Mi > 0.0001893939 & # lowest non-zero percentile
TravelDistance_Mi < 1.0812500000 & # 99th percentile
TravelTime_Sec > 10.050000 & # 2nd percentile
TravelTime_Sec < 293.000000 # 98th percentile
),
SpeedAvg_Mph,
SpeedAvg_Mph2
)
)
Investigation of SpeedAvg_Mph2.
Histogram of SpeedAvg_Mph2.
Speed_HistDen <- ggplot(filter(AllDays_NewTravelDist,
!is.na(SpeedAvg_Mph2)
),
aes(x = SpeedAvg_Mph2,
y = ..density..
)
) +
geom_histogram(binwidth = 5, fill = "lightblue", colour = "grey60", size = 0.2) +
geom_line(stat = "density", colour = "red") +
stat_bin(binwidth = 5,
geom = "text",
size = 2.5,
vjust = 1.5,
aes(label = format(..count.., big.mark = ",")
),
) +
# geom_text(aes(label = format(..count.., big.mark = ",")
# ),
# size = 3,
# nudge_y = (..count.. * 0.1)
# ) +
coord_cartesian(xlim = c(0, 70), ylim = c(0, 0.04)
) +
# theme(legend.position="none") +
labs(title = "Variation in Travel Speed",
x = "Average Speed (mph)",
y = "Density"
)
Speed_HistDen
Investigation of SpeedAvg_Mph2.
Histogram of SpeedAvg_Mph2 after removing outlier TravelTime_Sec and TravelDistance_Mi.
View(TravDistMiNew_Pctiles)
View(TravTimeHr_Pctiles)
SpeedNoOutlier_HistDen <- ggplot(filter(AllDays_NewTravelDist,
!is.na(SpeedAvg_Mph2) &
TravelDistance_Mi_New > 0.077841005 & # 5th percentile
# TravelDistance_Mi_New < 1.0812500000 & # 99th percentile
TravelTime_Sec > 12.100000 # 4th percentile
# TravelTime_Sec < 293.000000 # 98th percentile
),
aes(x = SpeedAvg_Mph2,
y = ..density..
)
) +
geom_histogram(binwidth = 5, fill = "lightblue", colour = "grey60", size = 0.2) +
geom_line(stat = "density", colour = "red") +
stat_bin(binwidth = 5,
geom = "text",
size = 2.5,
vjust = 1.5,
aes(label = format(..count.., big.mark = ",")
),
) +
# geom_text(aes(label = format(..count.., big.mark = ",")
# ),
# size = 3,
# nudge_y = (..count.. * 0.1)
# ) +
coord_cartesian(xlim = c(0, 70), ylim = c(0, 0.04)
) +
# theme(legend.position="none") +
labs(title = "Variation in Travel Speed",
subtitle = "(removed low outliers of Travel Distance and Travel Time)",
x = "Average Speed (mph)",
y = "Density"
)
SpeedNoOutlier_HistDen
Investigation of SpeedAvg_Mph2.
New dataset (NoOutliers_TravelDistNTime) when removing outlier low values of TravelDistance_Mi_New and TravelTime_Sec.
View(TravDistMiNew_Pctiles)
View(TravTimeHr_Pctiles)
NoOutliers_TravelDistNTime <- filter(AllDays_NewTravelDist,
TravelDistance_Mi_New > .077841005 & # 5th percentile
# TravelDistance_Mi_New < 1.0812500000 & # 99th percentile
TravelTime_Sec > 12.100000 # 4th percentile
# TravelTime_Sec < 293.000000 # 98th percentile
)
nrow(AllDays_NewTravelDist) - nrow(NoOutliers_TravelDistNTime)
str(NoOutliers_TravelDistNTime)
summary(NoOutliers_TravelDistNTime)
Investigation of SppedAvg_Mph2.
View(Speed_NoOut_Pctiles): Aproximately 90% of SpeedAvg_Mph2 values are between ~4mph and ~56mph.
Speed_NoOut_Ntile <- as.data.frame(NoOutliers_TravelDistNTime$SpeedAvg_Mph2) %>%
mutate(Pctile = ntile(NoOutliers_TravelDistNTime$SpeedAvg_Mph2, 100),
MinR = min_rank(NoOutliers_TravelDistNTime$SpeedAvg_Mph2),
PctR = percent_rank(NoOutliers_TravelDistNTime$SpeedAvg_Mph2),
PctR_Round = round(PctR, 2)
)
colnames(Speed_NoOut_Ntile)[1] <- "SpeedAvg_Mph2"
str(Speed_NoOut_Ntile)
Speed_NoOut_Ntile_Rows <- nrow(Speed_NoOut_Ntile)
View(tail(Speed_NoOut_Ntile, 500))
Speed_NoOut_Pctiles <- group_by(Speed_NoOut_Ntile,
PctR_Round
) %>%
summarise(
MinSpeedAtPctile = min(SpeedAvg_Mph2),
CntsAtPctile = n(),
PctsAtPctile = CntsAtPctile / Speed_NoOut_Ntile_Rows
) %>%
mutate(CumSumPAtP = cumsum(PctsAtPctile)
)
View(Speed_NoOut_Pctiles)
Investigation of SppedAvg_Mph2.
Exloring odd/impossible values.
# Exploring when SpeedAvg_Mph2 is NA -- does not occur at all
nrow(filter(NoOutliers_TravelDistNTime,
is.na(SpeedAvg_Mph2)
)
)
# Exploring when SpeedAvg_Mph2 is zero -- does not occur at all
nrow(filter(NoOutliers_TravelDistNTime,
SpeedAvg_Mph2 == 0
)
)
# examples where SpeedAvg_Mph2 < 3.2848770
View(filter(AllDays_NewTravelDist,
SpeedAvg_Mph2 > 0 &
SpeedAvg_Mph2 < 3.2848770
) %>%
arrange(SpeedAvg_Mph2)
)
# examples where SpeedAvg_Mph2 < 3.2848770
View(filter(AllDays_NewTravelDist,
(RowNum_OG >= 485338 & RowNum_OG <= 485358) | # 485348 -- Extreme travel time, Route Change
(RowNum_OG >= 346952 & RowNum_OG <= 346972) | # 346962 -- Extreme travel time, Route Change
(RowNum_OG >= 70494 & RowNum_OG <= 70514) | # 70504 -- Extreme travel time, Route Change
(RowNum_OG >= 2051846 & RowNum_OG <= 2051866) # 2051856 -- Extreme travel time, Route Change
)
)
Investigation of SpeedAvg_Mph2.
Limit the dataset based on SpeedAvg_Mph2.
NoOutliersSpeed <- filter(NoOutliers_TravelDistNTime,
between(SpeedAvg_Mph2,
4.069300, # 5th percentile
56.05651 #95th percentile
)
)
nrow(NoOutliers_TravelDistNTime) - nrow(NoOutliersSpeed)
summary(NoOutliersSpeed)
TravelTime now looks like it has some odd values on the high end. So let’s look at those.
View(TravTime_NoOut_Pctiles): Virtually all trips should take less than 5 minutes. (The 99th percentile of of TravelTime is approximately 8 minutes.)
TravTime_NoOut_Ntile <- as.data.frame(NoOutliersSpeed$TravelTime_Hr) %>%
mutate(Pctile = ntile(NoOutliersSpeed$TravelTime_Hr, 100),
MinR = min_rank(NoOutliersSpeed$TravelTime_Hr),
PctR = percent_rank(NoOutliersSpeed$TravelTime_Hr),
PctR_Round = round(PctR, 2)
)
colnames(TravTime_NoOut_Ntile)[1] <- "TravelTime_Hr"
str(TravTime_NoOut_Ntile)
TravTime_NoOut_Ntile_Rows <- nrow(TravTime_NoOut_Ntile)
View(tail(TravTime_NoOut_Ntile, 500))
TravTime_NoOut_Pctiles <- group_by(TravTime_NoOut_Ntile,
PctR_Round
) %>%
summarise(
MinTravTimeHrAtPctile = min(TravelTime_Hr),
CntsAtPctile = n(),
PctsAtPctile = CntsAtPctile / TravTime_NoOut_Ntile_Rows
) %>%
mutate(CumSumPAtP = cumsum(PctsAtPctile),
MinTravTimeSecAtPctile = MinTravTimeHrAtPctile * (60 * 60)
)
View(TravTime_NoOut_Pctiles)
Investigating odd TravelTime_Sec values.
Trips longer than ~8 minutes.
View(filter(NoOutliersSpeed,
TravelTime_Sec > 491 # min at the 100th percentile
) %>%
arrange(desc(TravelTime_Sec)
)
)
# examples of TravelTime_Sec values that are largest.
View(filter(NoOutliersSpeed,
(RowNum_OG >= 2071759 & RowNum_OG <= 2071779) | # 2071769 -- results from a route change, and a 3hr+ wait before the new route starts
(RowNum_OG >= 1473686 & RowNum_OG <= 1473706) | # 1473696 -- results from a route change, and a 3hr wait before the new route starts
(RowNum_OG >= 1222822 & RowNum_OG <= 1222842) | # 1222832 -- results from a route change, and a 3hr wait before the new route starts
(RowNum_OG >= 3046089 & RowNum_OG <= 3046109) # 3046099 -- results from a route change, and a 3hr wait before the new route starts
)
)
# examples of TravelTime_Sec values that are the smallest of the large.
View(filter(NoOutliersSpeed,
(RowNum_OG >= 3044689 & RowNum_OG <= 3044709) | # 3044699 -- results from a route change
(RowNum_OG >= 3022358 & RowNum_OG <= 3022378) | # 3022368 -- results from a route change
(RowNum_OG >= 2993016 & RowNum_OG <= 2993036) | # 2993026 -- results from a previous route change (change occurred in deleted row)
(RowNum_OG >= 2683703 & RowNum_OG <= 2683723) # 2683713 -- results from a previous route change (change occurred in deleted row)
)
)
Let’s look at the TravelTime_Sec values and route changes (DirChange2).
The 99th percentile of TravelTime_Sec for both, all trips, and just those trips NOT involving route changes (DirChange2 = “Same”), is approximately 5min (300 sec).
Nota Bene: The percentile calculation here is defined slightly different than in most of the above analyses (which get the lowest value in the bin created by 100 ntiles).
summary(select(NoOutliersSpeed,
TravelTime_Sec
)
)
summary(select(filter(NoOutliersSpeed,
DirChange2 == "Same"
),
TravelTime_Sec
)
)
summary(select(filter(NoOutliersSpeed,
DirChange2 == "Change"
),
TravelTime_Sec
)
)
TravTimeSec_Qtiles_df <- data.frame(PctValue = seq(0, 100, 1),
All = seq(1, 101, 1),
Same = seq(1, 101, 1),
Change = seq(1, 101, 1)
)
TravTimeSec_Qtiles_df[ , 2] <- quantile(select(NoOutliersSpeed,
TravelTime_Sec
),
probs = seq(0, 1, 0.01),
na.rm = TRUE
)
TravTimeSec_Qtiles_df[ , 3] <- quantile(select(filter(NoOutliersSpeed,
DirChange2 == "Same"
),
TravelTime_Sec
),
probs = seq(0, 1, 0.01),
na.rm = TRUE
)
TravTimeSec_Qtiles_df[ , 4] <- quantile(select(filter(NoOutliersSpeed,
DirChange2 == "Change"
),
TravelTime_Sec
),
probs = seq(0, 1, 0.01),
na.rm = TRUE
)
View(TravTimeSec_Qtiles_df)
Limit the dataset now based on TravelTime_Sec.
UpperLimitTravTime <- filter(NoOutliersSpeed,
TravelTime_Sec <= 491 # min at the 100th percentile
)
nrow(NoOutliersSpeed) - nrow(UpperLimitTravTime)
str(UpperLimitTravTime)
summary(UpperLimitTravTime)
Investigation of Dwell_Time2 (how long the bus is at a stop).
Differences between Dwell_Time (by WMATA) and Dwell_Time2 (by me) appear to be due to switches in RouteAlt. WMATA calculates Dwell_Time by an unknown process. The WMATA calculation is equal to my calculation, except for the records immedaitely before and after a RouteAlt switch (DirChange2).
View(filter(AllDays_NewOrder,
Dwell_Time != Dwell_Time2
)
)
# Examples where the Dwell_Time and Dwell_Time2 are different
View(filter(AllDays_NewOrder,
( (RowNum_OG >= 65 & RowNum_OG <= 85) | # 75
(RowNum_OG >= 162 & RowNum_OG <= 192) | # 172
(RowNum_OG >= 431952 & RowNum_OG <= 431972) | # 431962
(RowNum_OG >= 434595 & RowNum_OG <= 434615) # 434605 -- this record is NOT a route switch, but does has a Sequence switch (Me: should there really be a route switch here?)
)
)
)
Investigation of Dwell_Time2 (how long the bus is at a stop).
First, create some “rank” stats. View(DT2_Pctiles): 95% of Dwell_Time2s are <= 23 seconds…but some weird (e.g., nearly 2 hour Dwell_Time2s exist).
DwellTime2_Ntile <- as.data.frame(AllDays_NewOrder$Dwell_Time2) %>%
mutate(Pctile = ntile(AllDays_NewOrder$Dwell_Time2, 100),
MinR = min_rank(AllDays_NewOrder$Dwell_Time2),
PctR = percent_rank(AllDays_NewOrder$Dwell_Time2),
PctR_Round = round(PctR, 2)
)
colnames(DwellTime2_Ntile)[1] <- "Dwell_Time2"
str(DwellTime2_Ntile)
DwellTime2_Ntile_Rows <- nrow(DwellTime2_Ntile)
View(tail(DwellTime2_Ntile, 500))
DwellTime2_Pctiles <- group_by(DwellTime2_Ntile,
PctR_Round
) %>%
summarise(
MinDwellAtPctile = min(Dwell_Time2),
CntsAtPctile = n(),
PctsAtPctile = CntsAtPctile / DwellTime2_Ntile_Rows
) %>%
mutate(CumSumPAtP = cumsum(PctsAtPctile)
)
View(DwellTime2_Pctiles)
Investigation of Dwell_Time2 (how long the bus is at a stop).
Histogram of Dwell_Time2.
DwellTime2_HistDen <- ggplot(AllDays_NewOrder, aes(x = Dwell_Time2, y = ..density..)) +
geom_histogram(binwidth = 1, fill = "lightblue", colour = "grey60", size = 0.2) +
geom_line(stat = "density", colour = "red") +
coord_cartesian(xlim = c(1, 25), ylim = c(0, 0.05)
) +
xlab("Time a Bus Stays at a Stop (sec)") +
ylab("Density") +
# theme(legend.position="none") +
ggtitle(expression(atop("Variation in How Long a Bus Stays at a Stop"
# ,atop(italic("xxxxx"),"")
)
)
)
DwellTime2_HistDen
Investigation of Dwell_Time2 (how long the bus is at a stop).
Looking at some weirdly long Dwell_Time2 values.
View(arrange(AllDays_NewOrder,
desc(Dwell_Time2)
)
)
# examples of extremely large Dwell_Time2s
View(filter(AllDays_NewOrder,
(RowNum_OG >= 292669 & RowNum_OG <= 292689) | # 292679
(RowNum_OG >= 531057 & RowNum_OG <= 531077) | # 531067
(RowNum_OG >= 1388627 & RowNum_OG <= 1388647) | # 1388637
(RowNum_OG >= 1645711 & RowNum_OG <= 1645731) # 1645721
)
)
View(filter(AllDays_NewOrder,
Dwell_Time2 == 0
)
)
Investigation of Delta_Time (how early or late the bus is).
View(DT2_Pctiles): 94% of Delta_Time values are between -236 seconds and 1,259 seconds. Roughly 66% of records are within 5 min late and 5 min early…but some weird (e.g., almost 50 minute late or 40 minute early) Delta_Times exist.
Note that Delta_Time is the difference from the scheduled bus arrival. So if two buses are scheduled to arrive at a destination at 10:00pm and 10:20pm, and if the 10:20pm bus has a Delta_Time of 5 minutes, there are 25 minutes between bus arrivals at the stop.
Also note that based on a comment at https://planitmetro.com/2016/11/16/data-download-metrobus-vehicle-location-data/, the Delta_Time values don’t appear to coincide with published bus schedules (e.g., the X2 departing every 8 minutes during peak hours).
DeltTime_Ntile <- as.data.frame(AllDays_NewOrder$Delta_Time) %>%
mutate(Pctile = ntile(AllDays_NewOrder$Delta_Time, 100),
MinR = min_rank(AllDays_NewOrder$Delta_Time),
PctR = percent_rank(AllDays_NewOrder$Delta_Time),
PctR_Round = round(PctR, 2)
)
colnames(DeltTime_Ntile)[1] <- "Delta_Time"
str(DeltTime_Ntile)
DeltTime_Ntile_Rows <- nrow(DeltTime_Ntile)
View(tail(DeltTime_Ntile, 500))
DeltTime_Pctiles <- group_by(DeltTime_Ntile,
PctR_Round
) %>%
summarise(
MinDeltTimeAtPctile = min(Delta_Time),
CntsAtPctile = n(),
PctsAtPctile = CntsAtPctile / DeltTime_Ntile_Rows
) %>%
mutate(CumSumPAtP = cumsum(PctsAtPctile)
)
View(DeltTime_Pctiles)
DeltTime_Pctiles
# ~66% of rows are between 5 min late and 5 min early
nrow(filter(AllDays_NewOrder,
Delta_Time >= -300 &
Delta_Time <= 300
)
) / nrow(AllDays_NewOrder)
# examples of weird large Delta_Times
View(filter(AllDays_NewOrder,
Delta_Time < -4202 |
Delta_Time > 1705
) %>%
arrange(desc(Delta_Time)
)
)
Investigation of Delta_Time (how early or late the bus is).
Delta_Time histogram.
DeltTime_HistDen <- ggplot(AllDays_NewOrder, aes(x = (Delta_Time / 60),
y = ..density..
)
) +
geom_histogram(binwidth = (5/60), fill = "lightblue", colour = "grey60", size = 0.2) +
geom_line(stat = "density", colour = "red") +
coord_cartesian(xlim = c(-5, 5)) +
xlab("Bus Lateness (min)") +
ylab("Density") +
# theme(legend.position="none") +
ggtitle(expression(atop("Variation in How Early/Late a Bus Is",
atop(italic("(positive values are late arrivals)"),
""
)
)
)
)
DeltTime_HistDen
Investigation of Delta_Time (how early or late the bus is).
Delta_Time boxplot.
# Count_Values is needed to display the medians on the box plots
Count_Values <- ddply(AllDays_NewOrder,
.(Event_Time_HrGroup),
summarise,
Value_Counts = median(Delta_Time / 60, na.rm = TRUE)
)
DeltTime_BoxPlot <- ggplot(AllDays_NewOrder,
aes(factor(Event_Time_HrGroup),
Delta_Time / 60,
fill = factor(Event_Time_HrGroup)
)
) +
geom_boxplot(outlier.colour="red", notch=TRUE) +
# coord_cartesian(ylim = c(-300, 1200)) +
coord_cartesian(ylim = c(-5, 20)) +
geom_text(data = Count_Values,
aes(y = Value_Counts,
label = format(round(Value_Counts, digits = 1),
nsmall = 1
)
),
size = 3,
vjust = -0.5
) +
xlab("Hour Group") +
ylab("Bus Lateness (minutes)") +
theme(legend.position="none", axis.text.x = element_text(angle=45)) +
#theme(legend.position="right", axis.text.x = element_blank()) +
ggtitle(expression(atop("How Early/Late is the Bus (by Hour Group)",
atop(italic("(positive values are late arrivals)"),
""
)
)
)
)
DeltTime_BoxPlot
Investigation of Delta_Time (how early or late the bus is).
Exploring “extreme” Delta_Times. First let’s get some “rank” stats.
View(DeltTime_Pctiles)
DeltTime_Pctiles
DeltTimeAbs_Ntile <- as.data.frame(abs(AllDays_NewOrder$Delta_Time)) %>%
mutate(Pctile = ntile(abs(AllDays_NewOrder$Delta_Time), 100),
MinR = min_rank(abs(AllDays_NewOrder$Delta_Time)),
PctR = percent_rank(abs(AllDays_NewOrder$Delta_Time)),
PctR_Round = round(PctR, 2)
)
colnames(DeltTimeAbs_Ntile)[1] <- "Delta_Time_Abs"
str(DeltTimeAbs_Ntile)
DeltTimeAbs_Ntile_Rows <- nrow(DeltTimeAbs_Ntile)
View(tail(DeltTimeAbs_Ntile, 500))
DeltTimeAbs_Pctiles <- group_by(DeltTimeAbs_Ntile,
PctR_Round
) %>%
summarise(
MinDeltTimeAtPctile = min(Delta_Time_Abs),
CntsAtPctile = n(),
PctsAtPctile = CntsAtPctile / DeltTime_Ntile_Rows
) %>%
mutate(CumSumPAtP = cumsum(PctsAtPctile)
)
View(DeltTimeAbs_Pctiles)
DeltTimeAbs_Pctiles
Investigation of Delta_Time (how early or late the bus is).
Exploring “extreme” Delta_Times. Then let’s calculate the percentage of buses that are 10 minutes (or more) late/early.
HrGroup_DeltaTime_All <- group_by(AllDays_NewOrder,
Event_Time_HrGroup
) %>%
summarise(EventAll_Cnt = n()
)
str(HrGroup_DeltaTime_All)
View(HrGroup_DeltaTime_All)
HrGroup_DeltaTime_Above10Min <- filter(AllDays_NewOrder,
abs(Delta_Time) >= 600
) %>%
group_by(Event_Time_HrGroup) %>%
summarise(EventAbove10_Cnt = n()
)
str(HrGroup_DeltaTime_Above10Min)
View(HrGroup_DeltaTime_Above10Min)
HrGroup_DeltaTimeCompare <- inner_join(HrGroup_DeltaTime_Above10Min,
HrGroup_DeltaTime_All,
by = c("Event_Time_HrGroup" = "Event_Time_HrGroup")
) %>%
mutate(PctEventsAbove10 = EventAbove10_Cnt / EventAll_Cnt)
View(HrGroup_DeltaTimeCompare)
Investigation of Delta_Time (how early or late the bus is).
Quickly plot these “extreme” Delta_Times.
DeltTime_Above10_Cols <- ggplot(HrGroup_DeltaTimeCompare,
aes(factor(Event_Time_HrGroup),
PctEventsAbove10
)
) +
geom_col(fill = "lightblue", colour = "grey60", size = 0.2) +
geom_text(aes(label = format(round(PctEventsAbove10, digits = 2),
nsmall = 2
)
),
size = 3,
nudge_y = (HrGroup_DeltaTimeCompare$PctEventsAbove10 * -0.1)
) +
# coord_cartesian(xlim = c(-5, 5)) +
xlab("Hour Group") +
ylab("Percent of All Bus Arrivals") +
theme(legend.position="none", axis.text.x = element_text(angle=45)) +
ggtitle(expression(atop("When is a Bus 10+ Minutes Late/Early"
# ,atop(italic("positive values are late arrivals"),
# ""
# )
)
)
)
DeltTime_Above10_Cols
Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).
Correlation.
DwellTDeltaT_Corr <- as.matrix(cor(x = AllDays_NewOrder$Dwell_Time2,
y = AllDays_NewOrder$Delta_Time,
use = "pairwise"
)
)
DwellTDeltaT_Corr
Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).
Next, let’s get a sample of data for plotting. Let’s do this for the full dataset (AllDays_NewOrder).
AllDays_NewOrder_10PctSamp <- sample_frac(AllDays_NewOrder, 0.1) %>%
select(Delta_Time,
Dwell_Time2
) %>%
mutate(DataSet = "AllData")
str(AllDays_NewOrder_10PctSamp)
Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).
Let’s also get a sample of data for plotting, but with a datset that removes outliers.
View(DeltTime_Pctiles)
View(DwellTime2_Pctiles)
AllDays_NewOrder_NoExtremes_10PctSamp <- filter(AllDays_NewOrder,
between(Delta_Time, -402, 1705) & # removes about 2% of Delta_Time values
between(Dwell_Time2, 1, 63) # removes about 2% of Dwell_Time2 values
) %>%
sample_frac(0.1) %>%
select(Delta_Time,
Dwell_Time2
) %>%
mutate(DataSet = "OutliersRemoved")
str(AllDays_NewOrder_NoExtremes_10PctSamp)
Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).
Plotting the data from the dataset that does not remove outliers.
DwellTDeltaT_Scatter <- ggplot(AllDays_NewOrder_10PctSamp,
aes(Dwell_Time2, Delta_Time)
) +
geom_point(shape = 1, alpha = 0.5) +
scale_shape(solid = FALSE) +
geom_smooth(method = "lm", colour = "red") +
# xlab("Time at Stop (sec)") +
# ylab("Lateness (sec)") +
annotate(label = lm_eqn(df = AllDays_NewOrder_10PctSamp,
y = AllDays_NewOrder_10PctSamp$Delta_Time,
x = AllDays_NewOrder_10PctSamp$Dwell_Time2
),
x = 2200,
y = 600,
geom = "text",
size = 3,
colour = "red",
parse = TRUE
) +
labs(title = "Lateness vs Time at Stop",
subtitle = "(no outliers removed)",
x = "Time at Stop (sec)",
y = "Lateness (sec)"
)
# ggtitle(expression(atop("Lateness vs Time at Stop"
# ,atop(italic("(no outliers removed)"),
# ""
# )
# )
# )
# )
# +
# geom_jitter()
DwellTDeltaT_Scatter
Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).
Plotting the data from the dataset that does remove outliers.
DwellTDeltaT_Scatter_NoExtremes <- ggplot(AllDays_NewOrder_NoExtremes_10PctSamp,
aes(Dwell_Time2, Delta_Time)
) +
geom_point(shape = 1, alpha = 0.5) +
scale_shape(solid = FALSE) +
geom_smooth(method = "lm", colour = "blue") +
# xlab("Time at Stop (sec)") +
# ylab("Lateness (sec)") +
annotate(label = lm_eqn(df = AllDays_NewOrder_NoExtremes_10PctSamp,
y = AllDays_NewOrder_NoExtremes_10PctSamp$Delta_Time,
x = AllDays_NewOrder_NoExtremes_10PctSamp$Dwell_Time2
),
x = 50,
y = -475,
geom = "text",
size = 3,
colour = "blue",
parse = TRUE
) +
labs(title = "Lateness vs Time at Stop",
subtitle = "(2% of outliers removed)",
x = "Time at Stop (sec)",
y = "Lateness (sec)"
)
# ggtitle(expression(atop("Lateness vs Time at Stop"
# ,atop(italic("(2% of outliers removed)"),
# ""
# )
# )
# )
# )
# +
# geom_jitter()
DwellTDeltaT_Scatter_NoExtremes
Quick investigation on the relationship between Dwell_Time2 (the time a bus is at a stop) and Delta_Time (how early/late the bus is).
Plotting the data from both datasets together.
CombinedData <- rbind(AllDays_NewOrder_10PctSamp,
AllDays_NewOrder_NoExtremes_10PctSamp
)
CombinedData$DataSet <- factor(CombinedData$DataSet)
str(CombinedData)
DwellTDeltaT_Scatter_Combined <- ggplot(CombinedData,
aes(x = Dwell_Time2,
y = Delta_Time,
colour = DataSet
)
) +
geom_point(shape = 1, alpha = 0.5) +
scale_shape(solid = FALSE) +
coord_cartesian(xlim = c(0, 500), ylim = c(-1000, 2000)
) +
geom_smooth(data = filter(CombinedData,
DataSet == "AllData"
),
method = "lm",
colour = "red"
) +
geom_smooth(data = filter(CombinedData,
DataSet == "OutliersRemoved"
),
method = "lm",
colour = "blue"
) +
# facet_wrap( ~ DataSet, ncol = 2) +
annotate(label = lm_eqn(df = AllDays_NewOrder_10PctSamp,
y = AllDays_NewOrder_10PctSamp$Delta_Time,
x = AllDays_NewOrder_10PctSamp$Dwell_Time2
),
x = 300,
y = -600,
geom = "text",
size = 3,
colour = "red",
parse = TRUE
) +
annotate(label = lm_eqn(df = AllDays_NewOrder_NoExtremes_10PctSamp,
y = AllDays_NewOrder_NoExtremes_10PctSamp$Delta_Time,
x = AllDays_NewOrder_NoExtremes_10PctSamp$Dwell_Time2
),
x = 300,
y = -800,
geom = "text",
size = 3,
colour = "blue",
parse = TRUE
) +
theme(legend.position = "bottom") +
labs(title = "Lateness vs Time at Stop",
x = "Time at Stop (sec)",
y = "Lateness (sec)"
)
# ggtitle(expression(atop("Lateness vs Time at Stop"
# ,atop(italic("2% of outliers removed"),
# ""
# )
# )
# )
# )
# +
# geom_jitter()
DwellTDeltaT_Scatter_Combined
Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.
When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayBmb3IgV01BVEEgTWV0cm9idXMgRGF0YSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2sgZm9yIGFuYWx5c2lzIHVzaW5nIGRhdGEgb24gdGhlIERDIEJ1cyBTeXN0ZW0gKFdNQVRBIE1ldHJvYnVzKS4gIFRoZSBkYXRhIHdlcmUgb2J0YWluZWQgaGVyZToKCmh0dHBzOi8vcGxhbml0bWV0cm8uY29tLzIwMTYvMTEvMTYvZGF0YS1kb3dubG9hZC1tZXRyb2J1cy12ZWhpY2xlLWxvY2F0aW9uLWRhdGEvCgpDb250cm9sICsgQWx0ICsgU2hpZnQgKyBtID0gcmVuYW1lIGluIHNjb3BlCgpMb2FkIHRoZSBwYWNrYWdlcyB0byBiZSB1c2VkLgpgYGB7ciBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KCmxpYnJhcnkoImpzb25saXRlIikKbGlicmFyeSgic3FsZGYiKQpsaWJyYXJ5KCJ0Y2x0ayIpCmxpYnJhcnkoInRpZHlyIikKbGlicmFyeSgicGx5ciIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgibWFncml0dHIiKQpsaWJyYXJ5KCJzdHJpbmdyIikKbGlicmFyeSgiZGF0YS50YWJsZSIpCmxpYnJhcnkoImx1YnJpZGF0ZSIpCmxpYnJhcnkoImdlb3NwaGVyZSIpCmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KCJnZ21hcCIpCmxpYnJhcnkoImdndmlzIikKbGlicmFyeSgicmJva2VoIikKbGlicmFyeSgicmdkYWwiKQpsaWJyYXJ5KCJtYXB0b29scyIpCgpgYGAKCgpHZXQgdGhlIEJ1cyBkYXRhLgoKRmlyc3QgbGV0J3MgY2hlY2sgdGhlIHdvcmtpbmcgZGlyZWN0b3J5LgpgYGB7cn0KCmdldHdkKCkKCmBgYAoKClRoZW4sIGFjdHVhbGx5IGdldCB0aGUgZGF0YS4KYGBge3IgZWNobyA9IEZBTFNFfQoKc2V0d2QoIi9Vc2Vycy9tZHR1cnNlL0Rlc2t0b3AvQW5hbHl0aWNzL0RDTWV0cm9CdXMvQnVzIEFWTCBPY3QgMjAxNiIpCgpmb3IgKGkgaW4gMzo3KXsKICBhc3NpZ24ocGFzdGUwKCJPY3QwIiwgaSwgIlJhdyIpLAogICAgICAgICByZWFkLmRlbGltKHBhc3RlMCgiMjAxNjEwMCIsIGksICJNZXRyb2J1c0FWTC50eHQiKSwKICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgbmEuc3RyaW5ncyA9IE5VTEwKICAgICAgICAgICAgICAgICAgICkKICAgICAgICApCiAgCiAgbWVzc2FnZSgiT2N0MCIsIGksICJSYXciKQogCiAgc3RyKGdldChwYXN0ZTAoIk9jdDAiLCBpLCAiUmF3IikKICAgICAgICAgKQogICAgICkKICB9CgpgYGAKCgpQdXQgdGhlIGRhaWx5IGRhdGEgdG9nZXRoZXIuCmBgYHtyfQoKQWxsRGF5cyA8LSBiaW5kX3Jvd3MobGlzdChPY3QwM1JhdywgT2N0MDRSYXcsIE9jdDA1UmF3LCBPY3QwNlJhdywgT2N0MDdSYXcpLAogICAgICAgICAgICAgICAgICAgICAuaWQgPSBjKCJncm91cCIpCiAgICAgICAgICAgICAgICAgICAgKQojIGRpbShBbGxEYXlzKQpzdHIoQWxsRGF5cykKCmBgYAoKCkRlbGV0aW5nIG9sZCBkYXRhIGZyYW1lcy4KYGBge3J9Cgpmb3IgKGkgaW4gMzo3KXsKICBybShsaXN0ID0gbHMocGF0dGVybiA9IHBhc3RlMCgiT2N0MCIsIGksICJSYXciKQogICAgICAgICAgICAgICkKICAgICkKICAKICBtZXNzYWdlKCJEZWxldGluZyBPY3QwIiwgaSwgIlJhdyIpCiAgfQoKYGBgCgoKVXBkYXRpbmcgdmFyaWFibGUgdHlwZXMuCgpUaGVuLCBzb3J0aW5nIHRoZSBkYXRhIGFuZCBhZGRpbmcgYSBSb3dOdW1iZXIgKHRvIGJlIHVzZWQgZm9yIGlkZW50aWZ5aW5nIHJvd3MgbGF0ZXIgaW4gdGhlIGFuYWx5c2VzLikKYGBge3J9CgpybShpKQoKCkFsbERheXMkZ3JvdXAgPC0gZmFjdG9yKEFsbERheXMkZ3JvdXApCkFsbERheXMkUm91dGVfRGlyZWN0aW9uIDwtIGZhY3RvcihBbGxEYXlzJFJvdXRlX0RpcmVjdGlvbikKQWxsRGF5cyRFdmVudF9UaW1lIDwtIGFzLlBPU0lYY3QoQWxsRGF5cyRFdmVudF9UaW1lLCBmb3JtYXQgPSAiJW0tJWQtJXkgJUk6JU06JVMgJXAiKQpBbGxEYXlzJERlcGFydHVyZV9UaW1lIDwtIGFzLlBPU0lYY3QoQWxsRGF5cyREZXBhcnR1cmVfVGltZSwgZm9ybWF0ID0gIiVtLSVkLSV5ICVJOiVNOiVTICVwIikKCnN0cihBbGxEYXlzKQoKCkFsbERheXNfU29ydGVkIDwtIGFycmFuZ2UoQWxsRGF5cywKICAgICAgICAgICAgICAgICAgICAgICAgICBCdXNfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZQogICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFJvd051bV9PRyA9IHJvd19udW1iZXIoKSAjIHRoaXMgaXMgdXNlZnVsIGluIGlkZW50aWZ5IHRoZSByb3cgbGF0ZXIgb24KICAgICAgICApCgpybShBbGxEYXlzKQpzdHIoQWxsRGF5c19Tb3J0ZWQpCgojIFZpZXcoaGVhZChBbGxEYXlzX1NvcnRlZCwgMTAwKSkKCmBgYAoKCkluc3BlY3RpbmcgdGhlIHZhbHVlcyBvZiBTdG9wX0lELCBhbmQgZmluZGluZyB0aGF0IGl0IGNhbiB0YWtlIHRoZSB2YWx1ZXMgIiIgKGJsYW5rKSBhbmQgIk5VTEwiLgpgYGB7cn0KClZpZXcoZ3JvdXBfYnkoQWxsRGF5c19Tb3J0ZWQsCiAgICAgICAgICAgICAgU3RvcF9JRAogICAgICAgICAgICAgKSAlPiUgCiAgICAgICBzdW1tYXJpc2UoCiAgICAgICAgIENudCA9IG4oKQogICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoU3RvcF9JRCkKICAgICkKClZpZXcoZmlsdGVyKEFsbERheXNfU29ydGVkLAogICAgICAgICAgICBpcy5uYShTdG9wX0lEKSB8CiAgICAgICAgICAgICAgU3RvcF9JRCA9PSAiIiB8CiAgICAgICAgICAgICAgU3RvcF9JRCA9PSAiTlVMTCIKICAgICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoU3RvcF9EZXNjKQogICAgKQoKYGBgCgoKQ3JlYXRpbmcgYSB0YWJsZSBvZiBkaXN0aW5jdCBTdG9wX0Rlc2MgdmFsdWVzIHdoZW4gU3RvcF9JRCBpcyAiIiAoYmxhbmspIG9yICJOVUxMIi4KYGBge3J9CgpTdG9wSURfTmV3IDwtIGZpbHRlcihBbGxEYXlzX1NvcnRlZCwKICAgICAgICAgICAgICAgICAgICAgaXMubmEoU3RvcF9JRCkgfAogICAgICAgICAgICAgICAgICAgICAgIFN0b3BfSUQgPT0gIiIgfAogICAgICAgICAgICAgICAgICAgICAgIFN0b3BfSUQgPT0gIk5VTEwiCiAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc2VsZWN0KFN0b3BfSUQsIFN0b3BfRGVzYykgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGFycmFuZ2UoU3RvcF9JRCwgU3RvcF9EZXNjKSAlPiUgCiAgbXV0YXRlKFN0b3BJRF9OZXcgPSAxOm5yb3coLikKICAgICAgICApCgpWaWV3KFN0b3BJRF9OZXcpCgpgYGAKCgpDcmVhdGluZyBhIGZ1bGwgdXBkYXRlZCB0YWJsZSBieSBmaWxsaW5nIGluIFN0b3BJRF9OZXcgZm9yIHdoZW4gU3RvcF9JRCBpcyAiIiAoYmxhbmspIG9yIE5VTEwuCmBgYHtyfQoKQWxsRGF5c19TdG9wSUROZXcgPC0gbGVmdF9qb2luKEFsbERheXNfU29ydGVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KFN0b3BJRF9OZXcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RvcF9EZXNjLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BJRF9OZXcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoIlN0b3BfRGVzYyIgPSAiU3RvcF9EZXNjIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFN0b3BJRF9DbGVhbiA9IGlmZWxzZShpcy5uYShTdG9wSURfTmV3KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdG9wSURfTmV3CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFN0b3BJRF9JbmRpY2F0b3IgPSBmYWN0b3IoaWZlbHNlKGlzLm5hKFN0b3BJRF9OZXcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSURfT0siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSURfQmFkIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICApCgpybShTdG9wSURfTmV3KQpybShBbGxEYXlzX1NvcnRlZCkKc3RyKEFsbERheXNfU3RvcElETmV3KQoKIyBWaWV3KHRhaWwoQWxsRGF5c19TdG9wSUROZXcsIDUwMCkpCiMgVmlldyhmaWx0ZXIoQWxsRGF5c19TdG9wSUROZXcsCiMgICAgICAgICAgICAgU3RvcF9EZXNjID09ICJNRVRST1dBWSBBTk5OT1VDRU1OVCBDT1JSIgojICAgICAgICAgICAgKQojICAgICApCgpgYGAKCgoKTGF0IExvbmcgc3RhdHMgZm9yIHB1bGxpbmcgaW4gWmlwIGNvZGVzIGxhdGVyLgpgYGB7cn0KCkxMX1N0YXRzIDwtIGdyb3VwX2J5KEFsbERheXNfU3RvcElETmV3LAogICAgICAgICAgICAgICAgICAgICBTdG9wSURfQ2xlYW4KICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzdW1tYXJpc2UoTGF0X01lYW4gPSBtZWFuKExhdGl0dWRlLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBMYXRfTWVkID0gbWVkaWFuKExhdGl0dWRlLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBMbmdfTWVhbiA9IG1lYW4oTG9uZ2l0dWRlLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBMbmdfTWVkID0gbWVkaWFuKExvbmdpdHVkZSwgbmEucm0gPSBUUlVFKQogICAgICAgICAgICkgJT4lIAogIG11dGF0ZShMYXRfTWVhTGVzc01lZCA9IExhdF9NZWFuIC0gTGF0X01lZCwKICAgICAgICAgTG5nX01lYUxlc3NNZWQgPSBMbmdfTWVhbiAtIExuZ19NZWQsCiAgICAgICAgIFJvd051bSA9IHJvd19udW1iZXIoKQogICAgICAgICkKCnN0cihMTF9TdGF0cykKc3VtbWFyeShMTF9TdGF0cykKClZpZXcoaGVhZChhcnJhbmdlKExMX1N0YXRzLAogICAgICAgICAgICAgICAgICBMYXRfTWVhTGVzc01lZAogICAgICAgICAgICAgICAgICksCiAgICAgICAgICA1MDAKICAgICAgICAgKQogICAgKQoKVmlldyhoZWFkKGFycmFuZ2UoTExfU3RhdHMsCiAgICAgICAgICAgICAgICAgIGRlc2MoTGF0X01lYUxlc3NNZWQpCiAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgIDUwMAogICAgICAgICApCiAgICApCgpWaWV3KGhlYWQoYXJyYW5nZShMTF9TdGF0cywKICAgICAgICAgICAgICAgICAgTG5nX01lYUxlc3NNZWQKICAgICAgICAgICAgICAgICApLAogICAgICAgICAgNTAwCiAgICAgICAgICkKICAgICkKClZpZXcoaGVhZChhcnJhbmdlKExMX1N0YXRzLAogICAgICAgICAgICAgICAgICBkZXNjKExuZ19NZWFMZXNzTWVkKQogICAgICAgICAgICAgICAgICksCiAgICAgICAgICA1MDAKICAgICAgICAgKQogICAgKQoKYGBgCgoKUHVsbGluZyBpbiBaaXAgQ29kZSBkYXRhIGZyb20gYXBpLmdlb25hbWVzLm9yZy4KYGBge3J9CgojIFVSTCBFWEFNUExFOgojIGh0dHA6Ly9hcGkuZ2VvbmFtZXMub3JnL2ZpbmROZWFyYnlQb3N0YWxDb2Rlc0pTT04/bGF0PTM4Ljg5NTYwJmxuZz0tNzYuOTQ4NzMmcmFkaXVzPTAmdXNlcm5hbWU9c3VwZXJtZGF0Cgp1cmxfMSA8LSAiaHR0cDovL2FwaS5nZW9uYW1lcy5vcmcvZmluZE5lYXJieVBvc3RhbENvZGVzSlNPTj9sYXQ9Igp1cmxfMiA8LSAiJmxuZz0iCnVybF8zIDwtICImcmFkaXVzPTAmdXNlcm5hbWU9Igp1c2VybmFtZSA8LSAic3VwZXJtZGF0IgoKCiMgbmVlZCB0byBncm91cCBpbiBidW5jaGVzIGFzIGh0dHA6Ly9hcGkuZ2VvbmFtZXMub3JnIGxpbWl0cyBwdWxscyB0byAyMDAwIHBlciBob3VyCgoKIyMjIyMgU3RvcmUgZXZlcnl0aGluZyBpbiBtdWx0aXBsZSBsaXN0cwpwYWdlczEgPC0gbGlzdCgpCgoKc3lzdGVtLnRpbWUoCiMgICBmb3IoaiBpbiAwOjUpewojICAgZm9yKGsgaW4gKChtYXhfcm93X3Blcl9ocipqKSArIDEpOihtYXhfcm93X3Blcl9ociooaisxKQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKIyAgICAgICl7CiMgICAgIAojICAgfQojIH0KZm9yKGkgaW4gMToxMDAwKXsKICBsYXQgPC0gZmlsdGVyKExMX1N0YXRzLAogICAgICAgICAgICAgICAgUm93TnVtID09IGkKICAgICAgICAgICAgICAgKSAlPiUKICAgIHNlbGVjdChMYXRfTWVkKQogIAogIGxuZyA8LSBmaWx0ZXIoTExfU3RhdHMsCiAgICAgICAgICAgICAgICBSb3dOdW0gPT0gaQogICAgICAgICAgICAgICApICU+JQogICAgc2VsZWN0KExuZ19NZWQpCiAgCiAgQVBJRGF0YTEgPC0gZnJvbUpTT04ocGFzdGUwKHVybF8xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVybF8yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsbmcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVybF8zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VybmFtZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgZmxhdHRlbiA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICkKICAKICBtZXNzYWdlKCJSZXRyaWV2aW5nIFppcCBDb2RlICIsIGkpCiAgCiAgcGFnZXMxW1tpXV0gPC0gQVBJRGF0YTEkcG9zdGFsQ29kZXMKICAKICAjIFN5cy5zbGVlcCgzOTAwKQp9CikKCiMgY2xhc3MoQVBJRGF0YTEpCiMgY2xhc3MoQVBJRGF0YTIkcG9zdGFsQ29kZXMpCiMgc3RyKEFQSURhdGExKQojIGhlYWQoQVBJRGF0YTEpCiMgY2xhc3MocGFnZXMxKQojIHN0cihwYWdlczEpCiMgbnJvdyhwYWdlMSkKIyBuY29sKHBhZ2UxKQojIHBhZ2VzMVtbMTE5OV1dCiMgcGFnZXMxW1syMDUxXV0KCgojIyMjIyBDb21iaW5lIHRoZSBsaXN0cyBpbnRvIG9uZSBwYWdlClppcHMxIDwtIHJiaW5kLnBhZ2VzKHBhZ2VzMVtzYXBwbHkocGFnZXMxLCBsZW5ndGgpID4gMF0pCgoKIyMjIyMgQ29tYmluZSBhbGwgcGFnZXMKWmlwc19BbGwgPC0gYmluZF9yb3dzKFppcHMwLAogICAgICAgICAgICAgICAgICAgICAgWmlwczEsCiAgICAgICAgICAgICAgICAgICAgICBaaXBzMiwKICAgICAgICAgICAgICAgICAgICAgIFppcHMzLAogICAgICAgICAgICAgICAgICAgICAgWmlwczQsCiAgICAgICAgICAgICAgICAgICAgICBaaXBzNSwKICAgICAgICAgICAgICAgICAgICAgIFppcHM2LAogICAgICAgICAgICAgICAgICAgICAgWmlwczcsCiAgICAgICAgICAgICAgICAgICAgICBaaXBzOCwKICAgICAgICAgICAgICAgICAgICAgIFppcHM5LAogICAgICAgICAgICAgICAgICAgICAgWmlwczEwLAogICAgICAgICAgICAgICAgICAgICAgIyBaaXBzMV9hLAogICAgICAgICAgICAgICAgICAgICAgLmlkID0gImlkIgogICAgICAgICAgICAgICAgICAgICApICU+JSAKICBtdXRhdGUoVW5pcXVlTGF0TG5nID0gcGFzdGUobGF0LCBsbmcsIHNlcCA9ICJfXyIpCiAgICAgICAgKQoKIyBzdHIoWmlwc19BbGwpCiMgVmlldyhoZWFkKFppcHNfQWxsKSkKCgojIHN0cihMTF9TdGF0cykKTExfU3RhdHNfVW5xTGF0TG5nIDwtIG11dGF0ZShMTF9TdGF0cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBVbmlxdWVMYXRMbmcgPSBwYXN0ZShMYXRfTWVkLCBMbmdfTWVkLCBzZXAgPSAiX18iKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKIyBzdHIoTExfU3RhdHNfVW5xTGF0TG5nKQojIFZpZXcoaGVhZChMTF9TdGF0c19VbnFMYXRMbmcpKQoKCkxMX1N0YXRzWmlwcyA8LSBsZWZ0X2pvaW4oTExfU3RhdHNfVW5xTGF0TG5nLAogICAgICAgICAgICAgICAgICAgICAgICAgIFppcHNfQWxsLAogICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiVW5pcXVlTGF0TG5nIiA9ICJVbmlxdWVMYXRMbmciKQogICAgICAgICAgICAgICAgICAgICAgICAgKQoKc3RyKExMX1N0YXRzWmlwcykKIyBWaWV3KGhlYWQoTExfU3RhdHNaaXBzKSkKCiMgTm90IHN1cmUgd2hleSB0aGVzZSBjb3VsZG4ndCBiZSBmb3VuZCAod2h5IHRoZXkncmUgTkEpClZpZXcoZmlsdGVyKExMX1N0YXRzWmlwcywKICAgICAgICAgICAgaXMubmEocG9zdGFsQ29kZSkKICAgICAgICAgICApCiAgICApCgpgYGAKCgpKb2luIHRvIGNyZWF0ZSBvbmUgZGF0YXNldCB0aGF0IGFsc28gaW5jbHVkZXMgWmlwIHZhcmlhYmxlcy4KYGBge3J9CgpybSh1cmxfMSwgdXJsXzIsIHVybF8zLCB1c2VybmFtZSwgcGFnZXMwLCBwYWdlczEsIHBhZ2VzMiwgcGFnZXMzLCBwYWdlczQsIHBhZ2VzNSwgcGFnZXM2LCBwYWdlczcsIHBhZ2VzOCwgcGFnZXM5LCBwYWdlczEwLCBpLCBsYXQsIGxuZywgQVBJRGF0YTAsIEFQSURhdGExLCBBUElEYXRhMiwgQVBJRGF0YTMsIEFQSURhdGE0LCBBUElEYXRhNSwgQVBJRGF0YTYsIEFQSURhdGE3LCBBUElEYXRhOCwgQVBJRGF0YTksIEFQSURhdGExMCwgTExfU3RhdHMsIExMX1N0YXRzX1VucUxhdExuZykKCgpBbGxEYXlzX1ppcHMgPC0gbGVmdF9qb2luKEFsbERheXNfU3RvcElETmV3LAogICAgICAgICAgICAgICAgICAgICAgICAgIExMX1N0YXRzWmlwcywKICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoIlN0b3BJRF9DbGVhbiIgPSAiU3RvcElEX0NsZWFuIikKICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHJlbmFtZShTdG9wX1N0YXRlID0gYWRtaW5Db2RlMSwKICAgICAgICAgU3RvcF9Db3VudHkgPSBhZG1pbk5hbWUyLAogICAgICAgICBTdG9wX0NpdHkgPSBwbGFjZU5hbWUsCiAgICAgICAgIFN0b3BfWmlwID0gcG9zdGFsQ29kZQogICAgICAgICApCgpybShBbGxEYXlzX1N0b3BJRE5ldywgTExfU3RhdHNaaXBzKQpzdHIoQWxsRGF5c19aaXBzKQoKYGBgCgoKVXBkYXRpbmcgdmFyaWFibGUgdHlwZXMuCmBgYHtyfQoKQWxsRGF5c19aaXBzJFN0b3BfU3RhdGUgPC0gZmFjdG9yKEFsbERheXNfWmlwcyRTdG9wX1N0YXRlKQpBbGxEYXlzX1ppcHMkU3RvcF9Db3VudHkgPC0gZmFjdG9yKEFsbERheXNfWmlwcyRTdG9wX0NvdW50eSkKQWxsRGF5c19aaXBzJFN0b3BfWmlwIDwtIGZhY3RvcihBbGxEYXlzX1ppcHMkU3RvcF9aaXApCkFsbERheXNfWmlwcyRTdG9wX0NpdHkgPC0gZmFjdG9yKEFsbERheXNfWmlwcyRTdG9wX0NpdHkpCgpBbGxEYXlzX1ppcHMkZGlzdGFuY2UgPC0gYXMubnVtZXJpYyhBbGxEYXlzX1ppcHMkZGlzdGFuY2UpCkFsbERheXNfWmlwcyRjb3VudHJ5Q29kZSA8LSBmYWN0b3IoQWxsRGF5c19aaXBzJGNvdW50cnlDb2RlKQpBbGxEYXlzX1ppcHMkYWRtaW5OYW1lMSA8LSBmYWN0b3IoQWxsRGF5c19aaXBzJGFkbWluTmFtZTEpCgpzdHIoQWxsRGF5c19aaXBzKQoKYGBgCgoKRmVhdHVyZSBlbmdpbmVlcmluZy4KCkluc3BlY3RpbmcgaW5jaWRlbmNlcyBvZiBjb25zZWN1dGl2ZSBTdG9wX0lEcy4gVGhpcyBpcyBkb25lIGJlY2F1c2UgaW52ZXN0aWdhdGlvbiBzaG93ZWQgdGhhdCBtYW55IGNvbnNldXRpdmUgZXZlbnRzIG9jY3VyciBhdCB0aGUgc2FtZSBTdG9wX0lELCBidXQgd2l0aCB2YXJpb3VzIER3ZWxsX1RpbWVzLCBPZG9tZXRlcl9EaXN0YW5jZXMsIGV0Yy4gIEFsbCBvZiB3aGljaCBhZmZlY3QgY2FsY3VsYXRpb25zIGFuZCBhbmFseXNlcy4KCkNyZWF0ZSBkYXRhIG9uIHRoZSBydW5zIChjb25zZWN1dGl2ZSBTdG9wX0lEcykuCmBgYHtyfQoKU3RvcElEX1J1bnMgPC0gcmxlKEFsbERheXNfWmlwcyRTdG9wSURfQ2xlYW4pCgpTdG9wSURfUnVucyRlbmRzIDwtIGN1bXN1bShTdG9wSURfUnVucyRsZW5ndGhzKQoKU3RvcElEX1J1bnMkc3RhcnRzIDwtIGlmZWxzZShpcy5uYShsYWcoU3RvcElEX1J1bnMkZW5kcykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWcoU3RvcElEX1J1bnMkZW5kcykgKyAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApCgpzdHIoU3RvcElEX1J1bnMpCiMgY2xhc3MoU3RvcElEX1J1bnMpCiMgCiMgU3RvcElEX1J1bnNfZGYgPC0gZGF0YS5mcmFtZSh1bmNsYXNzKFN0b3BJRF9SdW5zKSkKIyBzdHIoU3RvcElEX1J1bnNfZGYpCiMgY2xhc3MoU3RvcElEX1J1bnNfZGYpCiMgcm0oU3RvcElEX1J1bnNfZGYpCgpgYGAKCgpUcnlpbmcgdG8gbGluayBkYXRhIG9uIFJ1bnNHcm91cHMgd2l0aCB0aGUgb3JpZ2luYWwgZGF0YSAoQWxsRGF5c19Tb3J0ZWQpLiBUaGUgZ29hbCBpcyB0byBzZWxlY3Qgb25seSBvbmUgcmVjb3JkIHBlciBSdW5zR3JvdXAgLSB0aGF0IGJlaW5nIHRoZSByZWNvcmQgd2l0aCB0aGUgbG9uZ2VzdCBEd2VsbF9UaW1lLgoKSSBhdHRlbXB0ZWQgdGhpcyBjb21wdXRhdGlvbiB1c2luZyBib3RoIGRhdGEuZnJhbWVzIChkcGx5cikgYW5kIGRhdGEudGFibGVzIChkYXRhLnRhYmxlKS4gSG93ZXZlciwgd2l0aCAyLDgwOSwwNjIgcm93cyBpbiBvbmUgZGF0YXNldCBhbmQgMywxMTksNDQzIHJvd3MgaW4gdGhlIG90aGVyIGRhdGFzZXQsIHRoZSBjdXJyZW50IGNvbXB1dGF0aW9uIHRpbWUgaXMgb3ZlciA1IGRheXMuLi5zbyBJJ20gdHJ5aW5nIGEgZGlmZmVyZW50IHN0cmF0ZWd5IHRvIG9ubHkgc2VsZWN0IHRoZSBmaXJzdCByZWNvcmQgaW4gYSBydW4uCmBgYHtyfQoKIyBDcmVhdGUgYSBSdW5zR3JvdXAgdmFyaWFibGUgZm9yIGVhY2ggcnVuCiMgU3RvcElEX1J1bnNfZGYkUnVuc0dyb3VwIDwtIHBhc3RlMCgiZyIsIHNlcSgxOm5yb3coU3RvcElEX1J1bnNfZGYpCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQojIAojIHN0cihTdG9wSURfUnVuc19kZikKIyBoZWFkKFN0b3BJRF9SdW5zX2RmLCAyNSkKIyB0YWlsKFN0b3BJRF9SdW5zX2RmLCAyNSkKIyAKIyBTdG9wSURfUnVuc19kZiA8LSBTdG9wSURfUnVuc19kZiAlPiUgCiMgICBtdXRhdGUoUm93TnVtID0gcm93X251bWJlcigpCiMgICAgICAgICApCiMgCiMgc3RyKFN0b3BJRF9SdW5zX2RmKQojIGhlYWQoU3RvcElEX1J1bnNfZGYsIDI1KQojIHRhaWwoU3RvcElEX1J1bnNfZGYsIDI1KQojIAojIAojICMgQ29udmVydGluZyB0byBkYXRhLnRhYmxlcyBmb3IsIGhvcGVmdWxseSwgaW1wcm92ZWQgcGVyZm9ybWFuY2UgKHNwZWVkKSBpbiBjb21wdXRhdGlvbgojIFN0b3BJRF9SdW5zX2R0IDwtIGRhdGEudGFibGUoU3RvcElEX1J1bnNfZGYpCiMgc2V0a2V5KFN0b3BJRF9SdW5zX2R0LCBSb3dOdW0pCiMgc3RyKFN0b3BJRF9SdW5zX2R0KQojIAojIEFsbERheXNfU29ydGVkX2R0IDwtIGRhdGEudGFibGUoQWxsRGF5c19Tb3J0ZWQpCiMgc2V0a2V5KEFsbERheXNfU29ydGVkX2R0LCBSb3dOdW1fT0cpCiMgc3RyKEFsbERheXNfU29ydGVkX2R0KQojICMgcm0oQWxsRGF5c19Tb3J0ZWRfZHQpCiMgCiMgCiMgIyBBY3R1YWwgbG9vcCB0byBwZXJmb3JtIHRoZSBjb21wdXRhdGlvbnMgYW5kIGxpbmsgdG8gb3JpZ2luYWwgZGF0YSAoQWxsRGF5c19Tb3J0ZWRfZHQpCiMgR3JvdXBEYXRhIDwtIGxpc3QoKQojIGZvcihpIGluIDE6bnJvdyhTdG9wSURfUnVuc19kdCkKIyAgICApIHsKIyAgIGFzc2lnbihwYXN0ZTAoImdyb3VwXyIsIGkpLAojICAgICAgICAgICAgU3RvcElEX1J1bnNfZHRbUm93TnVtID09IGksIFJ1bnNHcm91cF0KIyAgICAgICAgICAgKQojIAojICAgICAjIyMjIyAgVGhlIGNvZGUgYmVsb3cgaXMgdGhlIHNhbWUgY29kZSBhcyBhYm92ZSwgYnV0IGRvbmUgd2l0aCBkcGx5ciAgIyMjIyMKIyAKIyAgICAgIyBhc3NpZ24ocGFzdGUwKCJncm91cF8iLCBpKSwKIyAgICMgICAgICAgIGZpbHRlcihTdG9wSURfUnVuc19kZiwKIyAgICMgICAgICAgICAgICAgICBSb3dOdW0gPT0gaQojICAgIyAgICAgICAgICAgICAgKSAlPiUgCiMgICAjICAgICAgICAgIHNlbGVjdChSdW5zR3JvdXApCiMgICAjICAgICAgICkKIyAKIyAgIGFzc2lnbihwYXN0ZTAoImdyb3VwXyIsIGksICJfc3RhcnQiKSwKIyAgICAgICAgICBTdG9wSURfUnVuc19kdFtSb3dOdW0gPT0gaSwgc3RhcnRzXQojICAgICAgICAgKQojIAojICAgYXNzaWduKHBhc3RlMCgiZ3JvdXBfIiwgaSwgIl9lbmQiKSwKIyAgICAgICAgICBTdG9wSURfUnVuc19kdFtSb3dOdW0gPT0gaSwgZW5kc10KIyAgICAgICAgICkKIyAKIyAgIGFzc2lnbihwYXN0ZTAoImdyb3VwXyIsIGksICJfcm93cyIpLAojICAgICAgICAgIEFsbERheXNfU29ydGVkX2R0W1Jvd051bV9PRyA+PSBhcy5udW1lcmljKGdldChwYXN0ZTAoImdyb3VwXyIsIGksICJfc3RhcnQiKQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJgojICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJvd051bV9PRyA8PSBhcy5udW1lcmljKGdldChwYXN0ZTAoImdyb3VwXyIsIGksICJfZW5kIikKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJ1bnNHcm91cCA6PSBhcy5jaGFyYWN0ZXIoZ2V0KHBhc3RlMCgiZ3JvdXBfIiwgaSkKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQojICAgICAgICAgICAgICAgICAgICAgICAgICAgXQojIAojICAgICAjIyMjIyAgVGhlIGNvZGUgYmVsb3cgaXMgdGhlIHNhbWUgYXMgdGhlIGNvZGUgYWJvdmUsIGJ1dCBkb25lIHdpdGggZHBseXIgICMjIyMjCiMgCiMgICAgICAgICAgIyBmaWx0ZXIoQWxsRGF5c19Tb3J0ZWQsCiMgICAgICAgICAgIyAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csCiMgICAgICAgICAgIyAgICAgICAgICAgICAgICBhcy5udW1lcmljKGdldChwYXN0ZTAoImdyb3VwXyIsIGksICJfc3RhcnQiKQojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiMgICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKIyAgICAgICAgICAjICAgICAgICAgICAgICAgIGFzLm51bWVyaWMoZ2V0KHBhc3RlMCgiZ3JvdXBfIiwgaSwgIl9lbmQiKQojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiMgICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgKQojICAgICAgICAgICMgICAgICAgICAgICAgICApCiMgICAgICAgICAgIyAgICAgICApICU+JSAKIyAgICAgICAgICAjICAgbXV0YXRlKFJ1bnNHcm91cCA9IGFzLmNoYXJhY3RlcihnZXQocGFzdGUwKCJncm91cF8iLCBpKQojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiMgICAgICAgICAgIyAgICAgICAgKQojICAgICAgICAgKQojIAojICAgR3JvdXBEYXRhW1tpXV0gPC0gZ2V0KHBhc3RlMCgiZ3JvdXBfIiwgaSwgIl9yb3dzIikpCiMgCiMgICBtZXNzYWdlKCJQcm9jZXNzaW5nIEdyb3VwICIsIGksICIgb2YgMiw4MDksMDYyIikKIyB9CiMgCiMgCiMgR3JvdXBEYXRhX2RmIDwtIHJiaW5kLmZpbGwoR3JvdXBEYXRhKQojIHN0cihHcm91cERhdGFfZGYpCiMgaGVhZChHcm91cERhdGFfZGYpCiMgdGFpbChHcm91cERhdGFfZGYpCiMgIyBybShHcm91cERhdGFfZGYpCiMgCiMgCiMgZ3JvdXBfMQojIGdyb3VwXzFfc3RhcnQKIyBncm91cF8xX2VuZAojIGdyb3VwXzFfcm93cwojIGdyb3VwXzJfcm93cwojIGdyb3VwXzNfcm93cwojIGdyb3VwXzUwX3Jvd3MKIyBzdHIoZ3JvdXBfNTBfcm93cykKIyBncm91cF8yODA5MDYyX3Jvd3MKIyBHcm91cERhdGFbWzFdXQojIEdyb3VwRGF0YVtbNTBdXQojIAojIAojICMjIyMjICBUZXN0aW5nIEFyZWEgKEJlbG93KSAgIyMjIyMKIyAjIyMjIyAgVGVzdGluZyBBcmVhIChCZWxvdykgICMjIyMjCiMgIyMjIyMgIFRlc3RpbmcgQXJlYSAoQmVsb3cpICAjIyMjIwojIAojICMgaGVhZChTdG9wSURfUnVucyRzdGFydHMsIDIwKQojICMgaGVhZChBbGxEYXlzX05ld09yZGVyJFN0b3BfSUQsIDIwKQojICMgCiMgIyAKIyAjIGRhdCA8LSBhcy5kYXRhLmZyYW1lKGMoMSwxLDcsNyw3LDksNiw4LDIsMiwyLDEsMSwxLDEsMSkpCiMgIyBjb2xuYW1lcyhkYXQpWzFdIDwtICJkYXQiCiMgIyByIDwtIHJsZShkYXQkZGF0KQojICMgZGF0JHJ1biA8LSByZXAociRsZW5ndGhzLCByJGxlbmd0aHMpCiMgIyBkYXQkcnVuTGFnIDwtIGxhZyhkYXQkcnVuKQojICMgZGF0JGNvbmQgPC0gcmVwKHIkdmFsdWVzLCByJGxlbmd0aHMpCiMgIyBkYXQKIyAjIFZpZXcoZGF0KQoKYGBgCgoKV2hlbiBjb25zZWN1dGl2ZSBTdG9wX0lEIG9jY3VycnMsIG9ubHkgdGFrZSB0aGUgZmlyc3Qgb2NjdXJyZW5jZS4gVGhpcyBpcyBkb25lIGJlY2F1c2UgdGhlIGNvbXB1dGF0aW9uIHRpbWUgdG8gc2VsZWN0IG9ubHkgdGhlIHJlY29yZCB3aXRoIHRoZSBsb25nZXN0IER3ZWxsX1RpbWUgZm9yIGVhY2ggcnVuIHdhcyB0b28gbG9uZyAob3ZlciA1IGRheXMpLgoKVGhpcyBpcyBwcm9iYWJseSBsZXNzIHRoYW4gaWRlYWwgd2l0aCByZWdhcmRzIHRvIER3ZWxsX1RpbWUsIGJ1dCBzaG91bGQgbm90IG1ha2UgbXVjaCBkaWZmZXJlbmNlIGZvciBjYWxjdWxhdGlvbnMgb2YgdHJhdmVsIHRpbWUsIHNwZWVkLCBldGMuCmBgYHtyfQoKQWxsRGF5c19GaXJzdFN0b3BJRCA8LSBBbGxEYXlzX1ppcHNbU3RvcElEX1J1bnMkc3RhcnRzLCBdCgpkaW0oQWxsRGF5c19aaXBzKQpkaW0oQWxsRGF5c19GaXJzdFN0b3BJRCkKCm5yb3coQWxsRGF5c19aaXBzKSAtIG5yb3coQWxsRGF5c19GaXJzdFN0b3BJRCkKCnJtKEFsbERheXNfWmlwcywgU3RvcElEX1J1bnMpCnN0cihBbGxEYXlzX0ZpcnN0U3RvcElEKQoKYGBgCgoKRmVhdHVyZSBlbmdpbmVlcmluZy4KCkNyZWF0aW5nIG5ldyB2YXJpYWJsZXMuCmBgYHtyfQoKQWxsRGF5c19BZGRWYXJzIDwtIG11dGF0ZShBbGxEYXlzX0ZpcnN0U3RvcElELAogICAgICAgICAgICAgICAgICAgICAgICAgIE9kb21ldGVyX0Rpc3RhbmNlX01pID0gT2RvbWV0ZXJfRGlzdGFuY2UgLyA1MjgwLCAjNSwyODAgZmVldCBpbiAxIG1pbGUKICAgICAgICAgICAgICAgICAgICAgICAgICBEd2VsbF9UaW1lMiA9IGFzLm51bWVyaWMoRGVwYXJ0dXJlX1RpbWUgLSBFdmVudF9UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX1lyID0gYXMuaW50ZWdlcih5ZWFyKEV2ZW50X1RpbWUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX010aCA9IGFzLmludGVnZXIobW9udGgoRXZlbnRfVGltZSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfRGF0ZSA9IGRheShFdmVudF9UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0RheSA9IHdkYXkoRXZlbnRfVGltZSwgbGFiZWwgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyID0gaG91cihFdmVudF9UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX01pbiA9IG1pbnV0ZShFdmVudF9UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyR3JvdXAgPSBmYWN0b3IoaWZlbHNlKEV2ZW50X1RpbWVfSHIgPCAzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMF8yIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEV2ZW50X1RpbWVfSHIgPCA2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwM181IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEV2ZW50X1RpbWVfSHIgPCA5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwNl84IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEV2ZW50X1RpbWVfSHIgPCAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcm91cDlfMTEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRXZlbnRfVGltZV9IciA8IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMTJfMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRXZlbnRfVGltZV9IciA8IDE4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMTVfMTciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRXZlbnRfVGltZV9IciA8IDIxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMThfMjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRXZlbnRfVGltZV9IciA8IDI0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMjFfMjMiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpKSkpKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJHcm91cDBfMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwM181IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR3JvdXA2XzgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcm91cDlfMTEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcm91cDEyXzE0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR3JvdXAxNV8xNyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyb3VwMThfMjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcm91cDIxXzIzIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJlZCA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICApCgpybShBbGxEYXlzX0ZpcnN0U3RvcElEKQpzdHIoQWxsRGF5c19BZGRWYXJzKQoKCiMgZ3JvdXBfYnkoQWxsRGF5c19BZGRWYXJzLAojICAgICAgICAgIEV2ZW50X1RpbWVfSHJHcm91cAojICAgICAgICAgKSAlPiUgCiMgICBzdW1tYXJpc2UoQ250cyA9IG4oKQojICAgICAgICAgICAgKQoKCiMgVmlldyhoZWFkKGZpbHRlcihBbGxEYXlzX0FkZFZhcnMsCiMgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyID09IDAKIyAgICAgICAgICAgICAgICAgKSwKIyAgICAgICAgICAgNTAKIyAgICAgICAgICApCiMgICAgICkKCiMgVmlldyhoZWFkKEFsbERheXNfQWRkVmFycywgNTApKQoKYGBgCgoKPCEtLSBGdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgdGhlIGRpc3RhbmNlIHRyYXZlbGVkIGJhc2VkIG9uIHRoZSBIYXZlcnNpbmUgZm9ybXVsYS4gIE9yaWdpbmFsIGNvZGUgZnJvbTogaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vZ3JlYXQtY2lyY2xlLWRpc3RhbmNlLWNhbGN1bGF0aW9ucy1pbi1yLyAtLT4KPCEtLSBgYGB7cn0gLS0+Cgo8IS0tIGdjZC5oZiA8LSBmdW5jdGlvbihsb25nMSwgbGF0MSwgbG9uZzIsIGxhdDIpIHsgLS0+CjwhLS0gICBSIDwtIDYzNzEgIyBFYXJ0aCBtZWFuIHJhZGl1cyBba21dIC0tPgo8IS0tICAgZGVsdGEubG9uZyA8LSAobG9uZzIgLSBsb25nMSkgLS0+CjwhLS0gICBkZWx0YS5sYXQgPC0gKGxhdDIgLSBsYXQxKSAtLT4KPCEtLSAgIGEgPC0gc2luKGRlbHRhLmxhdC8yKV4yICsgY29zKGxhdDEpICogY29zKGxhdDIpICogc2luKGRlbHRhLmxvbmcvMileMiAtLT4KPCEtLSAgIGMgPC0gMiAqIGFzaW4obWluKDEsc3FydChhKSkpIC0tPgo8IS0tICAgZCA9IFIgKiBjICogMC42MjEzNzEgIyAxIGttID0gMC42MjEzNzEgbWlsZXMgLS0+CjwhLS0gICByZXR1cm4oZCkgIyBEaXN0YW5jZSBpbiBtaWxlcyAtLT4KPCEtLSB9IC0tPgoKPCEtLSBgYGAgLS0+CgoKRmVhdHVyZSBlbmdpbmVlcmluZy4KCkNyZWF0aW5nIG1vcmUgdmFyaWFibGVzLiBDcmVhdGluZyBhIEJ1c0V2ZW50IHJvdyBudW1iZXIgZm9yIGZ1dHVyZSBpZGVudGlmaWNhdGlvbiBwdXJwb3Nlcy4gVGhlbiwgY3JlYXRpbmcgdmFyaW91cyB2YXJpYWJsZXMgdG8gYW5hbHl6ZSBkaXN0YW5jZSB0cmF2ZWxlZCBhbmQgc3BlZWQuCmBgYHtyfQoKQWxsRGF5c19CdXNEYXkgPC0gZ3JvdXBfYnkoQWxsRGF5c19BZGRWYXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICBCdXNfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfRGF0ZQogICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIG11dGF0ZShCdXNEYXlfRXZlbnROdW0gPSByb3dfbnVtYmVyKCksICAjIHVzZWQgdG8gaWRlbnRpZnkgQnVzIG1vdmVtZW50cyBvbiBhIHBhcnRpY3VsYXIgZGF0ZQogICAgICAgICAKICAgICAgICAgUm91dGVfTGFnMSA9IGxhZyhSb3V0ZSksICAjIHVzZWQgaW4gZnV0dXJlIGFuYWx5c2VzIHRvIGlkZW50aWZ5IFJvdXRlIGNoYW5nZXMKICAgICAgICAgUm91dGVBbHRfTGFnMSA9IGxhZyhSb3V0ZUFsdCksICAjIHVzZWQgaW4gZnV0dXJlIGFuYWx5c2VzIHRvIGlkZW50aWZ5IFJvdXRlQWx0IChkaXJlY3Rpb24pIGNoYW5nZXMKICAgICAgICAgCiAgICAgICAgIE9kb21ldGVyX0Rpc3RhbmNlX0xhZzEgPSBsYWcoT2RvbWV0ZXJfRGlzdGFuY2UpLAogICAgICAgICAKICAgICAgICAgTGF0aXR1ZGVfTDEgPSBsYWcoTGF0aXR1ZGUpLAogICAgICAgICBMb25naXR1ZGVfTDEgPSBsYWcoTG9uZ2l0dWRlKSwKICAgICAgICAgIyBMYXRfUmFkaWFuID0gTGF0aXR1ZGUqcGkvMTgwLAogICAgICAgICAjIExvbmdfUmFkaWFuID0gTG9uZ2l0dWRlKnBpLzE4MCwKICAgICAgICAgIyBMYXRfUmFkaWFuX0wxID0gbGFnKExhdF9SYWRpYW4pLAogICAgICAgICAjIExvbmdfUmFkaWFuX0wxID0gbGFnKExvbmdfUmFkaWFuKSwKICAgICAgICAgCiAgICAgICAgICMgYWNjb3VudGluZyBmb3IgcG90ZW50aWFsIG5lZ2F0aXZlIGRpc3RhbmNlcwogICAgICAgICBUcmF2ZWxEaXN0YW5jZV9GdCA9IGlmZWxzZShPZG9tZXRlcl9EaXN0YW5jZSA+IE9kb21ldGVyX0Rpc3RhbmNlX0xhZzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9kb21ldGVyX0Rpc3RhbmNlIC0gT2RvbWV0ZXJfRGlzdGFuY2VfTGFnMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSA9IFRyYXZlbERpc3RhbmNlX0Z0IC8gNTI4MCwgIzUsMjgwIGZlZXQgaW4gMSBtaWxlCiAgICAgICAgIAogICAgICAgICAjIFRyYXZlbERpc3RhbmNlX01pMiA9IGdjZC5oZihsb25nMSA9IExvbmdfUmFkaWFuX0wxLAogICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXQxID0gTGF0X1JhZGlhbl9MMSwKICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9uZzIgPSBMb25nX1JhZGlhbiwKICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF0MiA9IExhdF9SYWRpYW4KICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAKICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycyA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGlmZWxzZSgoaXMubmEoTG9uZ2l0dWRlX0wxKSB8IGlzLm5hKExhdGl0dWRlX0wxKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzdEhhdmVyc2luZShjYmluZChMb25naXR1ZGVfTDEsIExhdGl0dWRlX0wxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYmluZChMb25naXR1ZGUsIExhdGl0dWRlKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAqIDAuMDAwNjIxMzcxLCAjIDAuMDAwNjIxMzcxIG1pbGVzID0gMSBtZXRlcgogICAgICAgICAKICAgICAgICAgIyBhY2NvdW50aW5nIGZvciBwb3RlbnRpYWwgbmVnYXRpdmUgdGltZXMKICAgICAgICAgVHJhdmVsVGltZV9TZWMgPSBhcy5udW1lcmljKGlmZWxzZShFdmVudF9UaW1lID4gbGFnKERlcGFydHVyZV9UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lIC0gbGFnKERlcGFydHVyZV9UaW1lKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUcmF2ZWxUaW1lX0hyID0gVHJhdmVsVGltZV9TZWMgLyAzNjAwLCAjIDMsNjAwIHNlY29uZHMgaW4gMSBob3VyCiAgICAgICAgIAogICAgICAgICAjIGFjY291bnRpbmcgZm9yIHBvdGVudGlhbCBuZWdhdGl2ZSBvciB6ZXJvIHRyYXZlbCB0aW1lcwogICAgICAgICBTcGVlZEF2Z19NcGggPSBpZmVsc2UoVHJhdmVsVGltZV9IciA+IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSAvIFRyYXZlbFRpbWVfSHIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAKICAgICAgICAgU3RhcnRfSUQgPSBsYWcoU3RvcElEX0NsZWFuKSwKICAgICAgICAgU3RhcnRfRGVzYyA9IGxhZyhTdG9wX0Rlc2MpLAogICAgICAgICBTdGFydFN0b3BfSUQgPSBpZmVsc2UoaXMubmEoU3RhcnRfSUQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIk5VTEwiLCBTdG9wSURfQ2xlYW4sIHNlcCA9ICItLSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoU3RhcnRfSUQsIFN0b3BJRF9DbGVhbiwgc2VwID0gIi0tIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQoKCnJtKEFsbERheXNfQWRkVmFycykKc3RyKEFsbERheXNfQnVzRGF5KQoKIyBzdW1tYXJ5KEFsbERheXNfQnVzRGF5KQoKIyBWaWV3KHRhaWwoQWxsRGF5c19CdXNEYXksIDUwKSkKCmBgYAoKCkluc3BlY3RpbmcgZm9yIGlzc3VlcyB3aXRoIFN0YXJ0U3RvcF9JRCAod2hlcmUgdGhlIHZhbHVlIGlzIGVpdGhlciBOQSBvciBjb250YWlucyBOVUxMKS4gVGhleSBPTkxZIGV4aXN0IHdoZW4gQnVzRGF5X0V2ZW50TnVtID0gMSAod2hpY2ggaXMgYnkgZGVzaWduKS4gU28gZXZlcnl0aGluZyBsb29rcyBPSy4KYGBge3J9CgpWaWV3KGdyb3VwX2J5KEFsbERheXNfQnVzRGF5LAogICAgICAgICAgICAgIFN0YXJ0U3RvcF9JRAogICAgICAgICAgICAgKSAlPiUgCiAgICAgICBzdW1tYXJpc2UoCiAgICAgICAgIENudCA9IG4oKQogICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKGRlc2MoQ250KQogICAgICAgICAgICAgICkKICAgICkKClZpZXcoZmlsdGVyKEFsbERheXNfQnVzRGF5LAogICAgICAgICAgICAoaXMubmEoU3RhcnRTdG9wX0lEKSB8CiAgICAgICAgICAgICAgc3RyX2RldGVjdChTdGFydFN0b3BfSUQsICJOVUxMIikKICAgICAgICAgICAgKSAmCiAgICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtICE9IDEKICAgICAgICAgICApCiAgICApCgpgYGAKCgpTdGF0cyAocXVhbnRpbGVzKSBvdmVyYWxsIGZvciBUcmF2ZWxEaXN0YW5jZV9NaS4KYGBge3J9CgpRdWFudGlsZXNfZHQgPC0gQWxsRGF5c19CdXNEYXkgJT4lIAogIG11dGF0ZShURF9NaV9xMiA9IHF1YW50aWxlKHggPSBUcmF2ZWxEaXN0YW5jZV9NaSwgcHJvYnMgPSAwLjAyLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBURF9NaV9xOTggPSBxdWFudGlsZSh4ID0gVHJhdmVsRGlzdGFuY2VfTWksIHByb2JzID0gMC45OCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfU2VjX3EyID0gcXVhbnRpbGUoeCA9IFRyYXZlbFRpbWVfU2VjLCBwcm9icyA9IDAuMDIsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFRUX1NlY19xOTggPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9TZWMsIHByb2JzID0gMC45OCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfcTIgPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9IciwgcHJvYnMgPSAwLjAyLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9Icl9xOTggPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9IciwgcHJvYnMgPSAwLjk4LCBuYS5ybSA9IFRSVUUpCiAgICAgICAgKSAlPiUgCiAgZGF0YS50YWJsZSgpCgoKU3RhdHMgPC0gUXVhbnRpbGVzX2R0ICU+JSAKICBtdXRhdGUoVERfTWlfTWVhbiA9IG1lYW4oVHJhdmVsRGlzdGFuY2VfTWksIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFREX01pX01lYW5fRiA9IG1lYW4oVHJhdmVsRGlzdGFuY2VfTWlbVERfTWlfcTIgPD0gVHJhdmVsRGlzdGFuY2VfTWkgJiBUcmF2ZWxEaXN0YW5jZV9NaSA8PSBURF9NaV9xOThdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVERfTWlfTWVkID0gbWVkaWFuKFRyYXZlbERpc3RhbmNlX01pLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBURF9NaV9NZWRfRiA9IG1lZGlhbihUcmF2ZWxEaXN0YW5jZV9NaVtURF9NaV9xMiA8PSBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pIDw9IFREX01pX3E5OF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFREX01pX0NudCA9IHN1bSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpCiAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFREX01pX0NudF9GID0gc3VtKCFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaVtURF9NaV9xMiA8PSBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pIDw9IFREX01pX3E5OF0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIAogICAgICAgICBUVF9TZWNfTWVhbiA9IG1lYW4oVHJhdmVsVGltZV9TZWMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFRUX1NlY19NZWFuX0YgPSBtZWFuKFRyYXZlbFRpbWVfU2VjW1RUX1NlY19xMiA8PSBUcmF2ZWxUaW1lX1NlYyAmIFRyYXZlbFRpbWVfU2VjIDw9IFRUX1NlY19xOThdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9TZWNfTWVkID0gbWVkaWFuKFRyYXZlbFRpbWVfU2VjLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9TZWNfTWVkX0YgPSBtZWRpYW4oVHJhdmVsVGltZV9TZWNbVFRfU2VjX3EyIDw9IFRyYXZlbFRpbWVfU2VjICYgVHJhdmVsVGltZV9TZWMgPD0gVFRfU2VjX3E5OF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVFRfU2VjX0NudCA9IHN1bSghaXMubmEoVHJhdmVsVGltZV9TZWMpCiAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9TZWNfQ250X0YgPSBzdW0oIWlzLm5hKFRyYXZlbFRpbWVfU2VjW1RUX1NlY19xMiA8PSBUcmF2ZWxUaW1lX1NlYyAmIFRyYXZlbFRpbWVfU2VjIDw9IFRUX1NlY19xOThdCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICApLAoKICAgICAgICAgVFRfSHJfTWVhbiA9IG1lYW4oVHJhdmVsVGltZV9IciwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfTWVhbl9GID0gbWVhbihUcmF2ZWxUaW1lX0hyW1RUX0hyX3EyIDw9IFRyYXZlbFRpbWVfSHIgJiBUcmF2ZWxUaW1lX0hyIDw9IFRUX0hyX3E5OF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9Icl9NZWQgPSBtZWRpYW4oVHJhdmVsVGltZV9IciwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfTWVkX0YgPSBtZWRpYW4oVHJhdmVsVGltZV9IcltUVF9Icl9xMiA8PSBUcmF2ZWxUaW1lX0hyICYgVHJhdmVsVGltZV9IciA8PSBUVF9Icl9xOThdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9Icl9DbnQgPSBzdW0oIWlzLm5hKFRyYXZlbFRpbWVfSHIpCiAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFRUX0hyX0NudF9GID0gc3VtKCFpcy5uYShUcmF2ZWxUaW1lX0hyW1RUX0hyX3EyIDw9IFRyYXZlbFRpbWVfSHIgJiBUcmF2ZWxUaW1lX0hyIDw9IFRUX0hyX3E5OF0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICApICU+JSAKICBkYXRhLmZyYW1lKCkKCnJtKEFsbERheXNfQnVzRGF5KQpybShRdWFudGlsZXNfZHQpCnN0cihTdGF0cykKIyBWaWV3KGhlYWQoU3RhdHMsIDUwKSkKCmBgYAoKClN0YXRzIGZvciBTdGFydFN0b3BfSUQuCmBgYHtyfQoKUXVhbnRpbGVzX1NTX2R0IDwtIGdyb3VwX2J5KFN0YXRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RhcnRTdG9wX0lECiAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIG11dGF0ZShURF9NaV9TU19xNSA9IHF1YW50aWxlKHggPSBUcmF2ZWxEaXN0YW5jZV9NaSwgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBURF9NaV9TU19xOTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsRGlzdGFuY2VfTWksIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfU2VjX1NTX3E1ID0gcXVhbnRpbGUoeCA9IFRyYXZlbFRpbWVfU2VjLCBwcm9icyA9IDAuMDUsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFRUX1NlY19TU19xOTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9TZWMsIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfU1NfcTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9IciwgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9Icl9TU19xOTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9IciwgcHJvYnMgPSAwLjk1LCBuYS5ybSA9IFRSVUUpCiAgICAgICAgKSAlPiUgCiAgZGF0YS50YWJsZSgpCgoKU3RhdHNfU3RTdCA8LSBncm91cF9ieShRdWFudGlsZXNfU1NfZHQsCiAgICAgICAgICAgICAgICAgICAgICAgU3RhcnRTdG9wX0lECiAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBtdXRhdGUoVERfTWlfU1NfTWVhbiA9IG1lYW4oVHJhdmVsRGlzdGFuY2VfTWksIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFREX01pX1NTX01lYW5fRiA9IG1lYW4oVHJhdmVsRGlzdGFuY2VfTWlbVERfTWlfU1NfcTUgPD0gVHJhdmVsRGlzdGFuY2VfTWkgJiBUcmF2ZWxEaXN0YW5jZV9NaSA8PSBURF9NaV9TU19xOTVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVERfTWlfU1NfTWVkID0gbWVkaWFuKFRyYXZlbERpc3RhbmNlX01pLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBURF9NaV9TU19NZWRfRiA9IG1lZGlhbihUcmF2ZWxEaXN0YW5jZV9NaVtURF9NaV9TU19xNSA8PSBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pIDw9IFREX01pX1NTX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFREX01pX1NTX0NudCA9IHN1bSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFREX01pX1NTX0NudF9GID0gc3VtKCFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaVtURF9NaV9TU19xNSA8PSBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pIDw9IFREX01pX1NTX3E5NV0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIAogICAgICAgICBUVF9TZWNfU1NfTWVhbiA9IG1lYW4oVHJhdmVsVGltZV9TZWMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFRUX1NlY19TU19NZWFuX0YgPSBtZWFuKFRyYXZlbFRpbWVfU2VjW1RUX1NlY19TU19xNSA8PSBUcmF2ZWxUaW1lX1NlYyAmIFRyYXZlbFRpbWVfU2VjIDw9IFRUX1NlY19TU19xOTVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9TZWNfU1NfTWVkID0gbWVkaWFuKFRyYXZlbFRpbWVfU2VjLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9TZWNfU1NfTWVkX0YgPSBtZWRpYW4oVHJhdmVsVGltZV9TZWNbVFRfU2VjX1NTX3E1IDw9IFRyYXZlbFRpbWVfU2VjICYgVHJhdmVsVGltZV9TZWMgPD0gVFRfU2VjX1NTX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVFRfU2VjX1NTX0NudCA9IHN1bSghaXMubmEoVHJhdmVsVGltZV9TZWMpKSwKICAgICAgICAgVFRfU2VjX1NTX0NudF9GID0gc3VtKCFpcy5uYShUcmF2ZWxUaW1lX1NlY1tUVF9TZWNfU1NfcTUgPD0gVHJhdmVsVGltZV9TZWMgJiBUcmF2ZWxUaW1lX1NlYyA8PSBUVF9TZWNfU1NfcTk1XQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAoKICAgICAgICAgVFRfSHJfU1NfTWVhbiA9IG1lYW4oVHJhdmVsVGltZV9IciwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfU1NfTWVhbl9GID0gbWVhbihUcmF2ZWxUaW1lX0hyW1RUX0hyX1NTX3E1IDw9IFRyYXZlbFRpbWVfSHIgJiBUcmF2ZWxUaW1lX0hyIDw9IFRUX0hyX1NTX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9Icl9TU19NZWQgPSBtZWRpYW4oVHJhdmVsVGltZV9IciwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfU1NfTWVkX0YgPSBtZWRpYW4oVHJhdmVsVGltZV9IcltUVF9Icl9TU19xNSA8PSBUcmF2ZWxUaW1lX0hyICYgVHJhdmVsVGltZV9IciA8PSBUVF9Icl9TU19xOTVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9Icl9TU19DbnQgPSBzdW0oIWlzLm5hKFRyYXZlbFRpbWVfSHIpKSwKICAgICAgICAgVFRfSHJfU1NfQ250X0YgPSBzdW0oIWlzLm5hKFRyYXZlbFRpbWVfSHJbVFRfSHJfU1NfcTUgPD0gVHJhdmVsVGltZV9IciAmIFRyYXZlbFRpbWVfSHIgPD0gVFRfSHJfU1NfcTk1XQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICkgJT4lIAogIGRhdGEuZnJhbWUoKQoKcm0oU3RhdHMpCnJtKFF1YW50aWxlc19TU19kdCkKc3RyKFN0YXRzX1N0U3QpCiMgVmlldyhoZWFkKFN0YXRzX1N0U3QsIDUwKSkKCmBgYAoKClN0YXRzIGZvciBTdGFydFN0b3BfSUQgd2l0aCBFdmVudF9UaW1lX0hyR3JvdXAuCmBgYHtyfQoKUXVhbnRpbGVzX1NTSEdfZHQgPC0gZ3JvdXBfYnkoU3RhdHNfU3RTdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RhcnRTdG9wX0lELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyR3JvdXAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBtdXRhdGUoVERfTWlfU1NIR19xNSA9IHF1YW50aWxlKHggPSBUcmF2ZWxEaXN0YW5jZV9NaSwgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBURF9NaV9TU0hHX3E5NSA9IHF1YW50aWxlKHggPSBUcmF2ZWxEaXN0YW5jZV9NaSwgcHJvYnMgPSAwLjk1LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9TZWNfU1NIR19xNSA9IHF1YW50aWxlKHggPSBUcmF2ZWxUaW1lX1NlYywgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9TZWNfU1NIR19xOTUgPSBxdWFudGlsZSh4ID0gVHJhdmVsVGltZV9TZWMsIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfSHJfU1NIR19xNSA9IHF1YW50aWxlKHggPSBUcmF2ZWxUaW1lX0hyLCBwcm9icyA9IDAuMDUsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFRUX0hyX1NTSEdfcTk1ID0gcXVhbnRpbGUoeCA9IFRyYXZlbFRpbWVfSHIsIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKQogICAgICAgICkgJT4lIAogIGRhdGEudGFibGUoKQoKClN0YXRzX1N0U3RfSHJHcnAgPC0gZ3JvdXBfYnkoUXVhbnRpbGVzX1NTSEdfZHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RhcnRTdG9wX0lELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfSHJHcm91cAogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFREX01pX1NTSEdfTWVhbiA9IG1lYW4oVHJhdmVsRGlzdGFuY2VfTWksIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFREX01pX1NTSEdfTWVhbl9GID0gbWVhbihUcmF2ZWxEaXN0YW5jZV9NaVtURF9NaV9TU0hHX3E1IDw9IFRyYXZlbERpc3RhbmNlX01pICYgVHJhdmVsRGlzdGFuY2VfTWkgPD0gVERfTWlfU1NIR19xOTVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFREX01pX1NTSEdfTWVkID0gbWVkaWFuKFRyYXZlbERpc3RhbmNlX01pLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBURF9NaV9TU0hHX01lZF9GID0gbWVkaWFuKFRyYXZlbERpc3RhbmNlX01pW1REX01pX1NTSEdfcTUgPD0gVHJhdmVsRGlzdGFuY2VfTWkgJiBUcmF2ZWxEaXN0YW5jZV9NaSA8PSBURF9NaV9TU0hHX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBURF9NaV9TU0hHX0NudCA9IHN1bSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVERfTWlfU1NIR19DbnRfRiA9IHN1bSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWlbVERfTWlfU1NIR19xNSA8PSBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pIDw9IFREX01pX1NTSEdfcTk1XQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIAogICAgICAgICBUVF9TZWNfU1NIR19NZWFuID0gbWVhbihUcmF2ZWxUaW1lX1NlYywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgVFRfU2VjX1NTSEdfTWVhbl9GID0gbWVhbihUcmF2ZWxUaW1lX1NlY1tUVF9TZWNfU1NIR19xNSA8PSBUcmF2ZWxUaW1lX1NlYyAmIFRyYXZlbFRpbWVfU2VjIDw9IFRUX1NlY19TU0hHX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9TZWNfU1NIR19NZWQgPSBtZWRpYW4oVHJhdmVsVGltZV9TZWMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgIFRUX1NlY19TU0hHX01lZF9GID0gbWVkaWFuKFRyYXZlbFRpbWVfU2VjW1RUX1NlY19TU0hHX3E1IDw9IFRyYXZlbFRpbWVfU2VjICYgVHJhdmVsVGltZV9TZWMgPD0gVFRfU2VjX1NTSEdfcTk1XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVFRfU2VjX1NTSEdfQ250ID0gc3VtKCFpcy5uYShUcmF2ZWxUaW1lX1NlYykpLAogICAgICAgICBUVF9TZWNfU1NIR19DbnRfRiA9IHN1bSghaXMubmEoVHJhdmVsVGltZV9TZWNbVFRfU2VjX1NTSEdfcTUgPD0gVHJhdmVsVGltZV9TZWMgJiBUcmF2ZWxUaW1lX1NlYyA8PSBUVF9TZWNfU1NIR19xOTVdCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAoKICAgICAgICAgVFRfSHJfU1NIR19NZWFuID0gbWVhbihUcmF2ZWxUaW1lX0hyLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9Icl9TU0hHX01lYW5fRiA9IG1lYW4oVHJhdmVsVGltZV9IcltUVF9Icl9TU0hHX3E1IDw9IFRyYXZlbFRpbWVfSHIgJiBUcmF2ZWxUaW1lX0hyIDw9IFRUX0hyX1NTSEdfcTk1XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9Icl9TU0hHX01lZCA9IG1lZGlhbihUcmF2ZWxUaW1lX0hyLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBUVF9Icl9TU0hHX01lZF9GID0gbWVkaWFuKFRyYXZlbFRpbWVfSHJbVFRfSHJfU1NIR19xNSA8PSBUcmF2ZWxUaW1lX0hyICYgVHJhdmVsVGltZV9IciA8PSBUVF9Icl9TU0hHX3E5NV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBUVF9Icl9TU0hHX0NudCA9IHN1bSghaXMubmEoVHJhdmVsVGltZV9IcikpLAogICAgICAgICBUVF9Icl9TU0hHX0NudF9GID0gc3VtKCFpcy5uYShUcmF2ZWxUaW1lX0hyW1RUX0hyX1NTSEdfcTUgPD0gVHJhdmVsVGltZV9IciAmIFRyYXZlbFRpbWVfSHIgPD0gVFRfSHJfU1NIR19xOTVdCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICkgJT4lIAogIGRhdGEuZnJhbWUoKQoKcm0oU3RhdHNfU3RTdCkKcm0oUXVhbnRpbGVzX1NTSEdfZHQpCnN0cihTdGF0c19TdFN0X0hyR3JwKQojIFZpZXcoaGVhZChTdGF0c19TdFN0X0hyR3JwLCA1MCkpCgpgYGAKCgpGZWF0dXJlIGVuZ2luZWVyaW5nLgoKQ3JlYXRpbmcgYSBCdXNFdmVudFJvdXRlIHJvdyBudW1iZXIsIGFuZCBhIFJvdXRlQWx0X0xhZzEgaW5kaWNhdG9yIGZvciBmdXR1cmUgaWRlbnRpZmljYXRpb24gcHVycG9zZXMuIApgYGB7cn0KCiMgcm0oUXVhbnRpbGVzX2R0KQojIHJtKFF1YW50aWxlc19TU19kdCkKIyBybShBbGxEYXlzX0J1c0RheSkKIyBybShRdWFudGlsZXNfU1NIR19kdCkKIyBybShTdGF0c19TdFN0KQoKIyBBbGxEYXlzX0J1c0RheVJvdXRlIDwtIGdyb3VwX2J5KFN0YXRzX1N0U3RfSHJHcnAsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCdXNfSUQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0RhdGUsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSb3V0ZQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKIyAgIG11dGF0ZShSb3V0ZUFsdF9MYWcyID0gbGFnKFJvdXRlQWx0KSAgIyB1c2VkIGluIGZ1dHVyZSBhbmFseXNlcyB0byBpZGVudGlmeSBSb3V0ZUFsdCAoZGlyZWN0aW9uKSBjaGFuZ2VzCiMgICAgICAgICAgCiMgICAgICAgICAgIyBPZG9tZXRlcl9EaXN0YW5jZV9MYWcxID0gbGFnKE9kb21ldGVyX0Rpc3RhbmNlKSwKIyAgICAgICAgICAjIAojICAgICAgICAgICMgIyBhY2NvdW50aW5nIGZvciBwb3RlbnRpYWwgbmVnYXRpdmUgZGlzdGFuY2VzCiMgICAgICAgICAgIyBUcmF2ZWxEaXN0YW5jZV9GdCA9IGlmZWxzZShPZG9tZXRlcl9EaXN0YW5jZSA+PSBPZG9tZXRlcl9EaXN0YW5jZV9MYWcxLAojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgT2RvbWV0ZXJfRGlzdGFuY2UgLSBPZG9tZXRlcl9EaXN0YW5jZV9MYWcxLAojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEKIyAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKIyAgICAgICAgICAjIFRyYXZlbERpc3RhbmNlX01pID0gVHJhdmVsRGlzdGFuY2VfRnQgLyA1MjgwLCAjNSwyODAgZmVldCBpbiAxIG1pbGUKIyAgICAgICAgICAjIAojICAgICAgICAgICMgIyBhY2NvdW50aW5nIGZvciBwb3RlbnRpYWwgbmVnYXRpdmUgdGltZXMKIyAgICAgICAgICAjIFRyYXZlbFRpbWVfU2VjID0gYXMubnVtZXJpYyhpZmVsc2UoRXZlbnRfVGltZSA+PSBsYWcoRGVwYXJ0dXJlX1RpbWUpLAojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lIC0gbGFnKERlcGFydHVyZV9UaW1lKSwKIyAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEKIyAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiMgICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAojICAgICAgICAgICMgVHJhdmVsVGltZV9IciA9IFRyYXZlbFRpbWVfU2VjIC8gMzYwMCwgIyAzLDYwMCBzZWNvbmRzIGluIDEgaG91cgojICAgICAgICAgICMgCiMgICAgICAgICAgIyAjIGFjY291bnRpbmcgZm9yIHBvdGVudGlhbCBuZWdhdGl2ZSBvciB6ZXJvIHRyYXZlbCB0aW1lcwojICAgICAgICAgICMgU3BlZWRBdmdfTXBoID0gaWZlbHNlKFRyYXZlbFRpbWVfSHIgPiAwLAojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pIC8gVHJhdmVsVGltZV9IciwKIyAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICBOQQojICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgKQojICAgICAgICAgKSAlPiUgCiMgICBkYXRhLmZyYW1lKCkKIyAKIyBybShTdGF0c19TdFN0X0hyR3JwKQojIHN0cihBbGxEYXlzX0J1c0RheVJvdXRlKQoKYGBgCgoKRmVhdHVyZSBlbmdpbmVlcmluZy4KCkNhbGN1bGF0aW5nIGEgdmFyaWFibGUgdG8ga25vdyBpZiB0aGUgUm91dGVBbHQgY2hhbmdlZC4gQ291bGQgYmUgdXNlZnVsIGluIGhlbHBpbmcgaWRlbnRpZnlpbmcgd2VpcmRuZXNzIGluIGNhbGN1bGF0ZWQgZGlzdGFuY2VzIGFuZCBzcGVlZHMuCmBgYHtyfQoKIyBybShTdGF0c19TdFN0X0hyR3JwKQoKQWxsRGF5c19EaXJDaGFuZ2UgPC0gU3RhdHNfU3RTdF9IckdycCAlPiUgICMgQWxsRGF5c19CdXNEYXlSb3V0ZSAlPiUgCiAgbXV0YXRlKFJ0ZUNoYW5nZSA9IGlmZWxzZShSb3V0ZSA9PSBSb3V0ZV9MYWcxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNhbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNoYW5nZSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgUnRlQ2hhbmdlMiA9IGZhY3RvcihpZmVsc2UoaXMubmEoUnRlQ2hhbmdlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNoYW5nZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJ0ZUNoYW5nZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIERpckNoYW5nZSA9IGlmZWxzZShSb3V0ZUFsdCA9PSBSb3V0ZUFsdF9MYWcxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNhbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNoYW5nZSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgRGlyQ2hhbmdlMiA9IGZhY3RvcihpZmVsc2UoaXMubmEoRGlyQ2hhbmdlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNoYW5nZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpckNoYW5nZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICApCgojIHJtKEFsbERheXNfQnVzRGF5Um91dGUpCnJtKFN0YXRzX1N0U3RfSHJHcnApCnN0cihBbGxEYXlzX0RpckNoYW5nZSkKClZpZXcoZmlsdGVyKEFsbERheXNfRGlyQ2hhbmdlLAogICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgMjU3MDA2MCwgMjU3MDA4MCkKICAgICAgICAgICApICU+JSAKICAgICAgIHNlbGVjdCgtbWF0Y2hlcygiKHEoMnw1fCg5NSl8KDk4KSkpfE1lYW58TWVkfENudCIpCiAgICAgICAgICAgICApCiAgICApCgpgYGAKCgpSZS1vcmRlcmluZyB0aGUgdmFyaWFibGVzIHRvIGVhc2Ugd2l0aCBjb21wcmVoZW5zaW9uLgpgYGB7cn0KCkFsbERheXNfTmV3T3JkZXIgPC0gIHNlbGVjdChBbGxEYXlzX0RpckNoYW5nZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJvd051bV9PRywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFVuaXF1ZUxhdExuZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RhcnRTdG9wX0lELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgQnVzX0lELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgUm91dGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBSdGVDaGFuZ2UyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgUm91dGVBbHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFJvdXRlQWx0X0xhZzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEaXJDaGFuZ2UyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgUm91dGVfRGlyZWN0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RvcF9TZXF1ZW5jZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0YXJ0X0lELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RhcnRfRGVzYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgU3RvcF9JRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BJRF9DbGVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BJRF9JbmRpY2F0b3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdG9wX0Rlc2MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudHJ5Q29kZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BfU3RhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdG9wX0NvdW50eSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BfQ2l0eSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BfWmlwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X0Rlc2NyaXB0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9ZciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfTXRoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9EYXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9EYXksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9Ickdyb3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9NaW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVwYXJ0dXJlX1RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEd2VsbF9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRHdlbGxfVGltZTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWx0YV9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF0aXR1ZGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb25naXR1ZGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBIZWFkaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgT2RvbWV0ZXJfRGlzdGFuY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBPZG9tZXRlcl9EaXN0YW5jZV9MYWcxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgT2RvbWV0ZXJfRGlzdGFuY2VfTWksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9GdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX3EyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfcTk4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfcTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19xOTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU0hHX3E1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NIR19xOTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9NZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfTWVhbl9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfTWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTX01lYW5fRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTSEdfTWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTSEdfTWVhbl9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfTWVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfTWVkX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19NZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19NZWRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTSEdfTWVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NIR19NZWRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX0NudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX0NudF9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfQ250LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfQ250X0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU0hHX0NudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTSEdfQ250X0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19xMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19xOTgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfcTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfcTk1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTSEdfcTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NIR19xOTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfTWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19NZWFuX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfTWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19TU19NZWFuX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NIR19NZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTSEdfTWVhbl9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX01lZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19NZWRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19TU19NZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfTWVkX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NIR19NZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NIR19NZWRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19DbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfQ250X0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfQ250LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTX0NudF9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTSEdfQ250LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTSEdfQ250X0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxUaW1lX0hyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfcTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9xOTgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU19xNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTX3E5NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTSEdfcTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU0hHX3E5NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX01lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9NZWFuX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU19NZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfU1NfTWVhbl9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfU1NIR19NZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfU1NIR19NZWFuX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9NZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9NZWRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTX01lZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTX01lZF9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfU1NIR19NZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU0hHX01lZF9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfQ250LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfQ250X0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU19DbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9Icl9TU19DbnRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX0hyX1NTSEdfQ250LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfSHJfU1NIR19DbnRfRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNwZWVkQXZnX01waAogICAgICAgICAgICAgICAgICAgICAgICAgICApCgpybShBbGxEYXlzX0RpckNoYW5nZSkKc3RyKHNlbGVjdChBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgIC1tYXRjaGVzKCIocSgyfDV8KDk1KXwoOTgpKSl8TWVhbnxNZWR8Q250IikKICAgICAgICAgICkKICAgKQpzdHIoQWxsRGF5c19OZXdPcmRlcikKCiMgVmlldyhoZWFkKEFsbERheXNfTmV3T3JkZXIsIDUwMCkpCiMgVmlldyh0YWlsKEFsbERheXNfTmV3T3JkZXIsIDUwMCkpCgpgYGAKCgpTdW1tYXJpemluZyB0aGUgZGF0YSB0byBoZWxwIHNwb3QgYW5vbW9saWVzLgpgYGB7cn0KClZpZXcoZ3JvdXBfYnkoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgICBTdG9wX0NpdHkpICU+JSAKICAgICAgIHN1bW1hcmlzZShDbnRfTnVtID0gbigpLAogICAgICAgICAgICAgICAgIENudF9QY3QgPSAxMDAqQ250X051bSAvIChucm93KEFsbERheXNfTmV3T3JkZXIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKGRlc2MoQ250X051bSkpCikKCnN1bW1hcnkoQWxsRGF5c19OZXdPcmRlcikKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkuCgpWaWV3KFRyYXZEaXN0TWlfUGN0aWxlcyk6IDk5JSBvZiBUcmF2ZWxEaXN0YW5jZV9NaSBhcmUgYWJvdXQgMSBtaWxlIG9yIGxlc3MuLi5idXQgc29tZSB3ZWlyZCBUcmF2ZWxEaXN0YW5jZV9NaSB2YWx1ZXMgKGUuZy4sIDU4NCBtaWxlcyB0cmF2ZWxlZCkgZXhpc3QuCmBgYHtyfQoKVHJhdkRpc3RNaV9OdGlsZSA8LSBhcy5kYXRhLmZyYW1lKEFsbERheXNfTmV3T3JkZXIkVHJhdmVsRGlzdGFuY2VfTWkpICU+JSAKICBtdXRhdGUoI1BjdGlsZSA9IG50aWxlKEFsbERheXNfTmV3T3JkZXIkVHJhdmVsRGlzdGFuY2VfTWksIDEwMCksCiAgICAgICAgICNNaW5SID0gbWluX3JhbmsoQWxsRGF5c19OZXdPcmRlciRUcmF2ZWxEaXN0YW5jZV9NaSksCiAgICAgICAgIFBjdFIgPSBwZXJjZW50X3JhbmsoQWxsRGF5c19OZXdPcmRlciRUcmF2ZWxEaXN0YW5jZV9NaSksCiAgICAgICAgIFBjdFJfUm91bmQgPSByb3VuZChQY3RSLCAyKQogICAgICAgICkgCgpjb2xuYW1lcyhUcmF2RGlzdE1pX050aWxlKVsxXSA8LSAiVHJhdmVsRGlzdGFuY2VfTWkiCiMgc3RyKFRyYXZEaXN0TWlfTnRpbGUpCgpUcmF2RGlzdE1pX050aWxlX1Jvd3MgPC0gbnJvdyhUcmF2RGlzdE1pX050aWxlKQoKIyBWaWV3KHRhaWwoVHJhdkRpc3RNaV9OdGlsZSwgNTAwKSkKCgpUcmF2RGlzdE1pX1BjdGlsZXMgPC0gZ3JvdXBfYnkoVHJhdkRpc3RNaV9OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgTWluVHJhdkRpc3RNaUF0UGN0aWxlID0gbWluKFRyYXZlbERpc3RhbmNlX01pKSwKICAgIENudHNBdFBjdGlsZSA9IG4oKSwKICAgIFBjdHNBdFBjdGlsZSA9IENudHNBdFBjdGlsZSAvIFRyYXZEaXN0TWlfTnRpbGVfUm93cwogICkgJT4lIAogIG11dGF0ZShDdW1TdW1QQXRQID0gY3Vtc3VtKFBjdHNBdFBjdGlsZSkKICAgICAgICApCgpybShUcmF2RGlzdE1pX050aWxlKQpybShUcmF2RGlzdE1pX050aWxlX1Jvd3MpCgpWaWV3KFRyYXZEaXN0TWlfUGN0aWxlcykKVHJhdkRpc3RNaV9QY3RpbGVzCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFRyYXZlbERpc3RhbmNlX01pLgoKV2h5IGFyZSBzb21lIFRyYXZlbERpc3RhbmNlX01pICJOQSI/IEl0IGxvb2tzIGxpa2UgcGFydGlhbGx5IGJlY2F1c2UgdGhlIHJlY29yZHMgYXJlIHRoZSBmaXJzdCB0cmlwIG9mIHRoZSBkYXkgKGZvciB0aGF0IGJ1cyksIHNvIEkgcHVycG9zZWZ1bGx5IHNldCB0aGUgZGlzdGFuY2UgdG8gIk5BIi4gQW5vdGhlciByZWFzb24gaXMgZHVlIHRvIHRoZSBvZG9tZXRlciByZWNvcmRpbmcgYSB2YWx1ZSBsZXNzIHRoYW4gdGhlIHByZXZpb3VzIG9kb21ldGVyIHJlY29yZGluZy4gSW4gbW9zdCBjYXNlcywgSSBoYXZlIG5vIGV4cGxhbmF0aW9uIGZvciB0aGlzIC0gdGhvdWdoIEkgaGF2ZSBvYnNlcnZlZCBhYm91dCA2NyUgb2YgYWxsIGluc3RhbmNlcyB3aGVyZSBUcmF2ZWxEaXN0YW5jZV9NaSBpcyBOQSAob3RoZXIgdGhhbiBiZWNhdXNlIGl0J3MgdGhlIGZpcnN0IHJlY29yZCBvZiB0aGUgZGF5KSBhcmUgaW5zdGFuY2VzIHdoZXJlIERpckNoYW5nZTIgaXMgIkNoYW5nZSIuIFRoaXMgaXMgd2VpcmQgYW5kIHNob3VsZCBiZSBhc2tlZCB0byBXTUFUQS4KYGBge3J9CgojIFZpZXcoaGVhZChBbGxEYXlzX05ld09yZGVyLCA1MDApKQoKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtICE9IDEgIyBXaGVuIEJ1c0RheV9FdmVudE51bSA9PSAxLCBUcmF2ZWxEaXN0YW5jZV9NaSBpcyBOQSBieSBkZXNpZ24gKGRvbid0IHdhbnQgdG8gY2FsY3VsYXRlIGRpc3RhbmNlIGJhc2VkIG9uIHllc3RlcmRheSdzIHBvc2l0aW9uKQogICAgICAgICAgICkgJT4lIAogICAgICAgZ3JvdXBfYnkoU3RhcnRTdG9wX0lEKSAlPiUgCiAgICAgICBzdW1tYXJpc2UoQ250cyA9IHN1bShpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKGRlc2MoQ250cykKICAgICAgICAgICAgICApCiAgICApCgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICBTdGFydFN0b3BfSUQgPT0gIjEwMDAyNDUtLTEwMDAyMTEiCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBzZWxlY3QoUm93TnVtX09HLAogICAgICAgICAgICAgIFN0YXJ0U3RvcF9JRCwKICAgICAgICAgICAgICBFdmVudF9UaW1lLAogICAgICAgICAgICAgIEV2ZW50X1RpbWVfSHJHcm91cCwKICAgICAgICAgICAgICBCdXNfSUQsCiAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWksCiAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycywKICAgICAgICAgICAgICBURF9NaV9TU19NZWFuLAogICAgICAgICAgICAgIFREX01pX1NTX01lYW5fRiwKICAgICAgICAgICAgICBURF9NaV9TU0hHX01lYW4sCiAgICAgICAgICAgICAgVERfTWlfU1NIR19NZWFuX0YsCiAgICAgICAgICAgICAgVERfTWlfU1NfTWVkLAogICAgICAgICAgICAgIFREX01pX1NTX01lZF9GLAogICAgICAgICAgICAgIFREX01pX1NTSEdfTWVkLAogICAgICAgICAgICAgIFREX01pX1NTSEdfTWVkX0YsCiAgICAgICAgICAgICAgVERfTWlfU1NfQ250LAogICAgICAgICAgICAgIFREX01pX1NTX0NudF9GLAogICAgICAgICAgICAgIFREX01pX1NTSEdfQ250LAogICAgICAgICAgICAgIFREX01pX1NTSEdfQ250X0YKICAgICAgICAgICAgICApICU+JSAKICAgICAgIG11dGF0ZShSYXRpb19NZWFuVG9IdnJzID0gVERfTWlfU1NfTWVhbiAvIFRyYXZlbERpc3RhbmNlX01pX0h2cnMpICU+JSAKICAgICAgIGFycmFuZ2UoRXZlbnRfVGltZSkKICAgICkKClZpZXcoZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgIGlzLm5hKFRyYXZlbERpc3RhbmNlX01pKQogICAgICAgICAgICkKICAgICkKCiMgVGhlc2UgcmVjb3JkcyBhcmUgTkEgYmVjdWFzZSB0aGUgcmVjb3JkIGlzIHRoZSBmaXJzdCByZWNvcmQgb2YgdGhlIGRheSAodGhlIEV2ZW50X1RpbWVfRGF0ZSkKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDMyNiwgMzQ2KSB8ICMgMzM2CiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDU5MSwgNjExKSB8ICMgNjAxCiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDg0NSwgODY1KSAjIDg1NQogICAgICAgICAgICkKICAgICkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkuCgpUaGVzZSByZWNvcmRzIGFyZSBOQSBiZWN1YXNlIHRoZSBjdXJyZW50IHJlY29yZCBvZG9tZXRlciBpcyBsZXNzIHRoYW4gdGhlIHByZXZpb3VzIHJlY29yZCBvZG9tZXRlci4gVGhlb3JldGljYWxseSwgdGhpcyBzaG91bGQgTk9UIGhhcHBlbi4gTWU6IGl0IGFwcGVhcnMgdGhhdCBhYm91dCA2NyUgb2YgYWxsIGluc3RhbmNlcyB3aGVyZSBUcmF2ZWxEaXN0YW5jZV9NaSBpcyBOQSAob3RoZXIgdGhhbiBiZWNhdXNlIGl0J3MgdGggZmlyc3QgcmVjb3JkIG9mIHRoZSBkYXkpIGFyZSBpbnN0YW5jZXMgd2hlcmUgRGlyQ2hhbmdlMiBpcyAiQ2hhbmdlIi4gVGhpcyBpcyB3ZWlyZCBhbmQgc2hvdWxkIGJlIGFza2VkIHRvIFdNQVRBLgpgYGB7cn0KClZpZXcoZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCAxOTQsIDIxNCkgfCAjIDIwNAogICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCA0NDAsIDQ2MCkgfCAjIDQ1MAogICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCA0NzgsIDQ5OCkgfCAjIDQ4OAogICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCA1MTAsIDUzMCkgIyA1MjAKICAgICAgICAgICApCiAgICApCgpUZXN0VGFibGUgPC0gZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtICE9IDEKICAgICAgICAgICAgICAgICAgICkgJT4lIAogIG11dGF0ZShUcmF2ZWxEaXN0YW5jZV9OQSA9IGFzLmZhY3RvcihpZmVsc2UoaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRydWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZhbHNlIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICkgJT4lCiAgZ3JvdXBfYnkoRGlyQ2hhbmdlMiwgVHJhdmVsRGlzdGFuY2VfTkEpICU+JQogIHN1bW1hcmlzZShUcmF2RGlzdE1pX05BQ250cyA9IG4oKQogICAgICAgICAgICkKCiMgVGVzdFRhYmxlCgpUZXN0VGFibGVfU3ByZWFkIDwtIGFzLmRhdGEuZnJhbWUoc3ByZWFkKFRlc3RUYWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9OQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2RGlzdE1pX05BQ250cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzZWxlY3QoRmFsc2UsCiAgICAgICAgIFRydWUKICAgICAgICApCgpyb3cubmFtZXMoVGVzdFRhYmxlX1NwcmVhZCkgPC0gYygiQ2hhbmdlIiwgIlNhbWUiKQojIHN0cihUZXN0VGFibGVfU3ByZWFkKQojIFRlc3RUYWJsZV9TcHJlYWQKCnByb3AudGFibGUoYXMudGFibGUoYXMubWF0cml4KFRlc3RUYWJsZV9TcHJlYWQpCiAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIDEKICAgICAgICAgICkKCnByb3AudGFibGUoYXMudGFibGUoYXMubWF0cml4KFRlc3RUYWJsZV9TcHJlYWQpCiAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIDIKICAgICAgICAgICkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkuCgpMZXQncyBsb29rIGF0IGp1c3QgdGhlIFRyYXZlbERpc3RhbmNlX01pIHZhbHVlcyB0aGF0IGFyZSBOT1QgIk5BIi4KYGBge3J9CgpybShUZXN0VGFibGUsIFRlc3RUYWJsZV9TcHJlYWQpCgpUcmF2ZWxEaXN0YW5jZV9NaV9Ob05BIDwtIGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFRyYXZlbERpc3RhbmNlX01pICE9IDAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKZGltKEFsbERheXNfTmV3T3JkZXIpCmRpbShUcmF2ZWxEaXN0YW5jZV9NaV9Ob05BKQpucm93KEFsbERheXNfTmV3T3JkZXIpIC0gbnJvdyhUcmF2ZWxEaXN0YW5jZV9NaV9Ob05BKQoKc3RyKFRyYXZlbERpc3RhbmNlX01pX05vTkEpCnN1bW1hcnkoVHJhdmVsRGlzdGFuY2VfTWlfTm9OQSkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkuCgpMZXQncyBwbG90IGp1c3QgdGhlIFRyYXZlbERpc3RhbmNlX01pIHZhbHVlcyB0aGF0IGFyZSBOT1QgIk5BIi4KYGBge3J9CgpUcmF2RGlzdE1pX0hpc3REZW4gPC0gZ2dwbG90KHNlbGVjdChUcmF2ZWxEaXN0YW5jZV9NaV9Ob05BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBUcmF2ZWxEaXN0YW5jZV9NaSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IC4uZGVuc2l0eS4uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjA1LCBmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG91ciA9ICJncmV5NjAiLCBzaXplID0gMC4yKSArCiAgZ2VvbV9saW5lKHN0YXQgPSAiZGVuc2l0eSIsIGNvbG91ciA9ICJyZWQiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDEuNSksIHlsaW0gPSBjKDAsIDQuMCkKICAgICAgICAgICAgICAgICApICsKICBsYWJzKHRpdGxlID0gIlZhcmlhdGlvbiBpbiBEaXN0YW5jZSBCZXR3ZWVuIFN0b3BzIiwKICAgICAgIHggPSAiVHJhdmVsIERpc3RhbmNlIChtaWxlcykiLAogICAgICAgeSA9ICJEZW5zaXR5IgogICAgICApCgpUcmF2RGlzdE1pX0hpc3REZW4KCmBgYAoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaS4KCkxvb2tpbmcgYXQgdGhlIGV4dHJlbWVseSBsYXJnZSBUcmF2ZWxEaXN0YW5jZV9NaSB2YWx1ZXMuIFNvbWUgKGFwcm94IDI3JSkgb2YgVHJhdmVsRGlzdGFuY2VfTWkgdmFsdWVzID4gMSBtaWxlIGFyZSB3aGVuIHRoZSBEaXJDaGFuZ2UyIGNoYW5nZXMuLi5idXQgd2hhdCBhYm91dCB0aGUgb3RoZXIgfjczJT8KYGBge3J9CgpybShUcmF2ZWxEaXN0YW5jZV9NaV9Ob05BKQoKIyBleGFtcGxlcyBvZiB3ZWlyZGx5IGxhcmdlIFRyYXZlbERpc3RhbmNlX01pClZpZXcoZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pID4gMS4xNTg3MTIxMjEyICMgMS4xNTg3MTIxMjEyIGlzIHRoZSA5OXRoIHBlcmNlbnRpbGUKICAgICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoZGVzYyhUcmF2ZWxEaXN0YW5jZV9NaSkKICAgICAgICAgICAgICApCiAgICApCgoKIyBXaHkgYXJlIHRoZXNlIGV4dHJlbWVzPyAgQWlycG9ydHM/ICBCdXMgY29sbGVjdGlvbiBwb2ludHM/ClZpZXcoZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ5NDA0NCwgNDk0MDY0KSB8ICMgNDk0MDU0CiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ5NDI3MywgNDk0MjkzKSB8ICMgNDk0MjgzCiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ5NDYyNiwgNDk0NjQ2KSB8ICMgNDk0NjM2CiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDE2MTAxNTYsIDE2MTAxNzYpIHwgIyAxNjEwMTY2CiAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDIwNzMwNzQsIDIwNzMwOTQpICMgMjA3MzA4NAogICAgICAgICAgICkKICAgICkKCiMgQmVmb3JlIFJlbW92aW5nIFJ1bnMKIyBWaWV3KGZpbHRlcihBbGxEYXlzX1NvcnRlZCwKIyAgICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgNDk0MDQ0LCA0OTQwNjQpIHwgIyA0OTQwNTQKIyAgICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCA0OTQyNzMsIDQ5NDI5MykgfCAjIDQ5NDI4MwojICAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ5NDYyNiwgNDk0NjQ2KSB8ICMgNDk0NjM2CiMgICAgICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgMTYxMDE1NiwgMTYxMDE3NikgfCAjIDE2MTAxNjYKIyAgICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCAyMDczMDc0LCAyMDczMDk0KSAjIDIwNzMwODQKIyAgICAgICAgICAgICkKIyAgICAgKQoKIyBBZnRlciBSZW1vdmluZyBSdW5zCiMgVmlldyhmaWx0ZXIoQWxsRGF5c19GaXJzdFN0b3BJRCwKIyAgICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgNDk0MDQ0LCA0OTQwNjQpIHwgIyA0OTQwNTQKIyAgICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCA0OTQyNzMsIDQ5NDI5MykgfCAjIDQ5NDI4MwojICAgICAgICAgICAgICAgYmV0d2VlbihSb3dOdW1fT0csIDQ5NDYyNiwgNDk0NjQ2KSB8ICMgNDk0NjM2CiMgICAgICAgICAgICAgICBiZXR3ZWVuKFJvd051bV9PRywgMTYxMDE1NiwgMTYxMDE3NikgfCAjIDE2MTAxNjYKIyAgICAgICAgICAgICAgIGJldHdlZW4oUm93TnVtX09HLCAyMDczMDc0LCAyMDczMDk0KSAjIDIwNzMwODQKIyAgICAgICAgICAgICkKIyAgICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaS4KCkFueSByZWxhdGlvbiB3aXRoIERpckNoYW5nZTI/ICBEb2Vzbid0IGxvb2sgYXMgaWYgdGhpcyBpcyBzby4KYGBge3J9CgpFeHRyZW1lVHJhdkRpc3QgPC0gZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKFRyYXZlbERpc3RhbmNlX01pKQogICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFRyYXZEaXN0X0V4dHJlbWUgPSBpZmVsc2UoVHJhdmVsRGlzdGFuY2VfTWkgPiAxLjE1ODcxMjEyMTIsICMgMS4xNTg3MTIxMjEyIGlzIHRoZSA5OXRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJ1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZhbHNlIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIGdyb3VwX2J5KERpckNoYW5nZTIsIFRyYXZEaXN0X0V4dHJlbWUpICU+JSAKICBzdW1tYXJpc2UoVHJhdkRpc3RNSV9FeHRDbnRzID0gbigpCiAgICAgICAgICAgKQoKIyBFeHRyZW1lVHJhdkRpc3QKCgpFeHRyZW1lVHJhdkRpc3RfU3ByZWFkIDwtIGFzLmRhdGEuZnJhbWUoc3ByZWFkKEV4dHJlbWVUcmF2RGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2RGlzdF9FeHRyZW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZEaXN0TUlfRXh0Q250cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzZWxlY3QoRmFsc2UsCiAgICAgICAgIFRydWUKICAgICAgICApCgpyb3cubmFtZXMoRXh0cmVtZVRyYXZEaXN0X1NwcmVhZCkgPC0gYygiQ2hhbmdlIiwgIlNhbWUiKQojIHN0cihFeHRyZW1lVHJhdkRpc3RfU3ByZWFkKQojIEV4dHJlbWVUcmF2RGlzdF9TcHJlYWQKCnByb3AudGFibGUoYXMudGFibGUoYXMubWF0cml4KEV4dHJlbWVUcmF2RGlzdF9TcHJlYWQpCiAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIDEKICAgICAgICAgICkKCnByb3AudGFibGUoYXMudGFibGUoYXMubWF0cml4KEV4dHJlbWVUcmF2RGlzdF9TcHJlYWQpCiAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIDIKICAgICAgICAgICkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkuCgpMb29raW5nIGF0IHNwZWNpZmljIGJ1c2VzIGFuZCBTdGFydFN0b3BfSUQuCmBgYHtyfQoKcm0oRXh0cmVtZVRyYXZEaXN0LCBFeHRyZW1lVHJhdkRpc3RfU3ByZWFkKQoKVmlldyhhcnJhbmdlKGdyb3VwX2J5KEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICAgICAgICAgICBCdXNfSUQKICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgICAgICAgICAgICAgIHN1bW1hcmlzZShEaXN0VHJhdl9NZWFuID0gbWVhbihUcmF2ZWxEaXN0YW5jZV9NaSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgICAgICAgIERpc3RUcmF2X01lZCA9IG1lZGlhbihUcmF2ZWxEaXN0YW5jZV9NaSwgbmEucm0gPSBUUlVFKQogICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgZGVzYyhEaXN0VHJhdl9NZWQpCiAgICAgICAgICAgICkKICAgICkKCgojIGV4YW1wbGUgb2YgZXh0cmVtZWx5IHNtYWxsIFRyYXZlbERpc3RhbmNlX01pIHZhbHVlcyAobG9va3MgbGlrZSB0aGUgb2RvbWV0ZXIgd2Fzbid0IGZ1bmN0aW9uaW5nKQpWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICBCdXNfSUQgPT0gNjExMSB8CiAgICAgICAgICAgICAgQnVzX0lEID09IDcyMDEgfAogICAgICAgICAgICAgIEJ1c19JRCA9PSA4MDU4CiAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKEJ1c19JRCwgRXZlbnRfVGltZSkKICAgICkKCgpWaWV3KGFycmFuZ2UoZ3JvdXBfYnkoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgICAgICAgICAgIFN0YXJ0U3RvcF9JRAogICAgICAgICAgICAgICAgICAgICApICU+JSAKICAgICAgICAgICAgICAgc3VtbWFyaXNlKERpc3RUcmF2X01lYW4gPSBtZWFuKFRyYXZlbERpc3RhbmNlX01pLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgRGlzdFRyYXZfTWVkID0gbWVkaWFuKFRyYXZlbERpc3RhbmNlX01pLCBuYS5ybSA9IFRSVUUpCiAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICBkZXNjKERpc3RUcmF2X01lZCkKICAgICAgICAgICAgKQogICAgKQoKIyBleGFtcGxlIG9mIGV4dHJlbWVseSBsYXJnZSBUcmF2ZWxEaXN0YW5jZV9NaSB2YWx1ZXMuLi5ubyBpZGVhIHdoeS4uLgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICBTdGFydFN0b3BfSUQgPT0gIjEwMDM2NjUtLTEyIiB8CiAgICAgICAgICAgICAgU3RhcnRTdG9wX0lEID09ICIxMDAzNjY1LS01MDAxOTI1IiB8CiAgICAgICAgICAgICAgU3RhcnRTdG9wX0lEID09ICIzMDAxMDM4LS0zMDAyNTY1IgogICAgICAgICAgICkgJT4lIAogICAgICAgYXJyYW5nZShTdGFydFN0b3BfSUQsIEV2ZW50X1RpbWUpCiAgICApCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFRyYXZlbERpc3RhbmNlX01pICYgVHJhdmVsRGlzdGFuY2VfTWlfTmV3LgoKSWYgVHJhdmVsRGlzbnRhY2VfTWkgaXMgYmVsb3cgdGhlIDV0aCBwZXJjZW50aWxlIGZvciB0aGF0IFN0YXJ0U3RvcF9JRCwgb3IgaWYgVHJhdmVsRGlzbnRhY2VfTWkgaXMgYWJvdmUgdGhlIDk1dGggcGVyY2VudGlsZSBmb3IgdGhhdCBTdGFydFN0b3BfSUQsIG9yIGlmIFRyYXZlbERpc3RhbmNlX01pIGlzIE5BICh3aGVuIHRoZSBCdXNEYXlfRXZlbnROdW0gIT0xKSwgY29uc2lkZXIgdGhpcyBhbiBvdXRsaWVyLiAgSW4gdGhpcyBjYXNlLCByZXBsYWNlIHRoZSB2YWx1ZSB3aXRoIHRoZSBtZWFuIGZvciB0aGF0IFN0YXJ0U3RvcF9JRCBhbmQgSG91ckdyb3VwIChURF9NaV9TU0hHX01lYW5fRiksIG9yIGlmIHRoZXJlIGFyZSBub3QgZW5vdWdoIHZhbHVlcyBhdCB0aGUgSG91ckdyb3VwIGxldmVsLCByZXBsYWNlIGl0IHdpdGggdGhlIG1lYW4gZm9yIHRoYXQgU3RhcnRTdG9wX0lELgpgYGB7cn0KCiMgVmlldyh0YWlsKEFsbERheXNfTmV3T3JkZXIsIDUwMCkpCgpBbGxEYXlzX05ld1RyYXZlbERpc3QgPC0gCiAgbXV0YXRlKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ldyA9IGlmZWxzZSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChUcmF2ZWxEaXN0YW5jZV9NaSA8IFREX01pX1NTSEdfcTUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSA+IFREX01pX1NTSEdfcTk1CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU0hHX0NudF9GID49IDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NIR19NZWFuX0YsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpICYgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChUcmF2ZWxEaXN0YW5jZV9NaSA8IFREX01pX1NTSEdfcTUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSA+IFREX01pX1NTSEdfcTk1CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU0hHX0NudF9GIDwgMjAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19DbnRfRiA+PSAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTX01lYW5fRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKCFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaSkgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKFRyYXZlbERpc3RhbmNlX01pIDwgVERfTWlfU1NIR19xNSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pID4gVERfTWlfU1NIR19xOTUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTX0NudF9GIDwgMjAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19DbnQgPj0gMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19NZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtICE9IDEgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzICE9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtICE9IDEgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzID09IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU19NZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkpKSksCiAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ld19MYWJlbCA9IAogICAgICAgICAgIGZhY3RvcihpZmVsc2UoIWlzLm5hKFRyYXZlbERpc3RhbmNlX01pKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIChUcmF2ZWxEaXN0YW5jZV9NaSA8IFREX01pX1NTSEdfcTUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSA+IFREX01pX1NTSEdfcTk1CiAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBURF9NaV9TU0hHX0NudF9GID49IDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgIlREX01pX1NTSEdfTWVhbl9GIiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKCFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaSkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAoVHJhdmVsRGlzdGFuY2VfTWkgPCBURF9NaV9TU0hHX3E1IHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWkgPiBURF9NaV9TU0hHX3E5NQogICAgICAgICAgICAgICAgICAgICAgICAgICApICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NIR19DbnRfRiA8IDIwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfQ250X0YgPj0gMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAiVERfTWlfU1NfTWVhbl9GIiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKCFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaSkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAoVHJhdmVsRGlzdGFuY2VfTWkgPCBURF9NaV9TU0hHX3E1IHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWkgPiBURF9NaV9TU0hHX3E5NQogICAgICAgICAgICAgICAgICAgICAgICAgICApICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVERfTWlfU1NfQ250X0YgPCAyMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFREX01pX1NTX0NudCA+PSAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICJURF9NaV9TU19NZWFuIiwKICAgICAgICAgICAgICAgICAgaWZlbHNlKGlzLm5hKFRyYXZlbERpc3RhbmNlX01pKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEJ1c0RheV9FdmVudE51bSAhPSAxICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycyAhPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgIlRyYXZlbERpc3RhbmNlX01pX0h2cnMiLAogICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoVHJhdmVsRGlzdGFuY2VfTWkpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgQnVzRGF5X0V2ZW50TnVtICE9IDEgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzID09IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAiVERfTWlfU1NfTWVhbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiVHJhdmVsRGlzdGFuY2VfTWkiCiAgICAgICAgICAgICAgICAgICAgICAgICkpKSkpCiAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3SHZycyA9IGlmZWxzZSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWlfSHZycykgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycyAhPSAwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChUcmF2ZWxEaXN0YW5jZV9NaV9OZXcgPCBURF9NaV9xMiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcgPiBURF9NaV9xOTgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnNfTGFiZWwgPQogICAgICAgICAgIGZhY3RvcihpZmVsc2UoIWlzLm5hKFRyYXZlbERpc3RhbmNlX01pX0h2cnMpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycyAhPSAwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgKFRyYXZlbERpc3RhbmNlX01pX05ldyA8IFREX01pX3EyIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3ID4gVERfTWlfcTk4CiAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAiVHJhdmVsRGlzdGFuY2VfTWlfSHZycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhcy5jaGFyYWN0ZXIoVHJhdmVsRGlzdGFuY2VfTWlfTmV3X0xhYmVsKQogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgU3BlZWRBdmdfTXBoX05ld0h2cnMgPSBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzIC8gVHJhdmVsVGltZV9IcgogICAgICAgICkKCnN0cihBbGxEYXlzX05ld1RyYXZlbERpc3QpCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFRyYXZlbERpc3RhbmNlX01pICYgVHJhdmVsRGlzdGFuY2VfTWlfSHZycyAmIFRyYXZlbERpc3RhbmNlX01pX05ldy4KClF1aWNrIHN1bW1hcnkgYW5kIHRoZW4gY29ycmVsYXRpb24gY2FsY3VsYXRpb24uCmBgYHtyfQoKcm0oQWxsRGF5c19OZXdPcmRlcikKCgojIDM4IHJvd3MgbWVldCB0aGlzIGNyaXRlcmlhIGFueW1vcmUgIC0tICBhcHBlYXJzIHRvIGJlIHRoZSBjYXNlIHdoZW4gYm90aCB0aGUgTGF0IExvbmcgY2FsY3VsYXRpb25zLCBhbmQgdGhlIFRyYXZlbERpc3RhbmNlIGNhbGN1bGF0aW9ucyBkaWQgbm90IGZ1bmN0aW9uIHByb3Blcmx5LgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgIGlzLm5hKFRyYXZlbERpc3RhbmNlX01pX05ldykgJgogICAgICAgICAgICAgIEJ1c0RheV9FdmVudE51bSAhPSAxCiAgICAgICAgICAgKQogICAgKQoKVmlldyhBbGxEYXlzX05ld1RyYXZlbERpc3QgJT4lIAogICAgICAgYXJyYW5nZShkZXNjKFRyYXZlbERpc3RhbmNlX01pX05ldykpICU+JSAKICAgICAgIGhlYWQoNTAwKQogICAgKQoKc3VtbWFyeShzZWxlY3QoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSwKICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycywKICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3LAogICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzCiAgICAgICAgICAgICAgKQogICAgICAgKQoKc3VtbWFyeShzZWxlY3QoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgICAgICAgICAgIEJ1c0RheV9FdmVudE51bSAhPSAxCiAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzLAogICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcsCiAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMKICAgICAgICAgICAgICApCiAgICAgICApCgoKY29yKHNlbGVjdChBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWksCiAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycywKICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcsCiAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3SHZycwogICAgICAgICAgKSwKICAgIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiCiAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzX0xhYmVsICYgVHJhdmVsRGlzdGFuY2VfTWlfTmV3SHZyc19MYWJlbC4KClNob3cgaG93IHRoZSBsYWJlbHMgY2hhbmdlZC4KYGBge3J9Cgpncm91cF9ieShBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ld19MYWJlbCwKICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3SHZyc19MYWJlbAogICAgICAgICkgJT4lIAogIHN1bW1hcmlzZShDbnROdW0gPSBuKCksCiAgICAgICAgICAgIENudFBjdCA9IGZvcm1hdChDbnROdW0gLyBucm93KEFsbERheXNfTmV3VHJhdmVsRGlzdCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2llbnRpZmljID0gOTk5OQogICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgKSAlPiUgCiAgYXJyYW5nZShkZXNjKENudFBjdCkKICAgICAgICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaSAmIFRyYXZlbERpc3RhbmNlX01pX0h2cnMgJiBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcuCgpHcmFwaGluZyB0aGUgdHdvIG1ldGhvZHMgb2YgY2FsY3VsYXRpbmcgVHJhdmVsRGlzdGFuY2VfTWkuCgpGaXJzdCwgbGV0J3MgZ2V0IGNyZWF0ZSBhIGZ1bmN0aW9uIHRvIHBsb3QgdGhlIGxpbmVyIG1vZGVsIGVxdWF0aW9uLgpgYGB7cn0KCmxtX2VxbiA8LSBmdW5jdGlvbihkZiwgeSwgeCl7CiAgbSA8LSBsbSh5IH4geCwgZGYpCiAgCiAgbCA8LSBsaXN0KGEgPSBmb3JtYXQoY29lZihtKVsxXSwgZGlnaXRzID0gMiksCiAgICAgICAgICAgIGIgPSBmb3JtYXQoYWJzKGNvZWYobSlbMl0pLCBkaWdpdHMgPSAyKSwKICAgICAgICAgICAgczEgPSBpZmVsc2UodGVzdCA9IGNvZWYobSlbMl0gPiAwLAogICAgICAgICAgICAgICAgICAgICAgICB5ZXMgPSAiKyIsCiAgICAgICAgICAgICAgICAgICAgICAgIG5vID0gIi0iCiAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgcjIgPSBmb3JtYXQoc3VtbWFyeShtKSRyLnNxdWFyZWQsCiAgICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDMKICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgKQogIAogIGVxIDwtIHN1YnN0aXR1dGUoaXRhbGljKHkpID09IGF+fnMxfn5iICUuJSBpdGFsaWMoeCkqIiwifn5pdGFsaWMocileMn4iPSJ+cjIsCiAgICAgICAgICAgICAgICAgICBsCiAgICAgICAgICAgICAgICAgICkKICAKICBhcy5jaGFyYWN0ZXIoYXMuZXhwcmVzc2lvbihlcSkKICAgICAgICAgICAgICApICAgICAgICAgICAgIAp9CgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFRyYXZlbERpc3RhbmNlX01pICYgVHJhdmVsRGlzdGFuY2VfTWlfTmV3SHZycy4KClNjYXR0ZXIgcGxvdCAodXNpbmcgYSAxMCUgc2FtcGxlIHRvIG1ha2luZyBwbG90dGluZyB0aW1lIGZhc3RlciBhbmQgdG8gcmVkdWNlIHVuLW5lZWRlZCBkYXRhIGluIHRoZSAic2FtZSIgc3Bsb3QpLgpgYGB7cn0KCnNldC5zZWVkKDEyMzQ1Njc4OSkKQWxsRGF5c19OZXdUcmF2ZWxEaXN0XzEwUGN0IDwtIGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIWlzLm5hKFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHJlbmFtZShEaXN0TWV0aG9kID0gVHJhdmVsRGlzdGFuY2VfTWlfTmV3SHZyc19MYWJlbCkgJT4lIAogIHNhbXBsZV9mcmFjKDAuMSkKCgpUcmF2RGlzdF9NaVZzQ2FsYyA8LSBnZ3Bsb3Qoc2VsZWN0KEFsbERheXNfTmV3VHJhdmVsRGlzdF8xMFBjdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpc3RNZXRob2QKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IERpc3RNZXRob2QKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQiLCJibHVlIiwgImdyZWVuIiwgIm9yYW5nZSIsICJibGFjayIpCiAgICAgICAgICAgICAgICAgICAgICkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAxLCBhbHBoYSA9IDAuNSkgKwogIHNjYWxlX3NoYXBlKHNvbGlkID0gRkFMU0UpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvdXIgPSAiYmx1ZSIpICsKICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEsIGNvbG91ciA9ICJyZWQiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDEuNSksIHlsaW0gPSBjKDAsIDEuNSkKICAgICAgICAgICAgICAgICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEuNSwgMC4yNSkKICAgICAgICAgICAgICAgICAgICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEuNSwgMC4yNSkKICAgICAgICAgICAgICAgICAgICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgI2MoMC44NSwgMC40MCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpCiAgICAgICApICsKICBhbm5vdGF0ZShsYWJlbCA9IGxtX2VxbihkZiA9IEFsbERheXNfTmV3VHJhdmVsRGlzdF8xMFBjdCwKICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gQWxsRGF5c19OZXdUcmF2ZWxEaXN0XzEwUGN0JFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBBbGxEYXlzX05ld1RyYXZlbERpc3RfMTBQY3QkVHJhdmVsRGlzdGFuY2VfTWlfTmV3SHZycwogICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAjIHggPSA2MiwKICAgICAgICAgICAjIHkgPSAyMCwKICAgICAgICAgICB4ID0gMC43MCwKICAgICAgICAgICB5ID0gMC4wMCwKICAgICAgICAgICBnZW9tID0gInRleHQiLAogICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgIGNvbG91ciA9ICJibHVlIiwKICAgICAgICAgICBwYXJzZSA9IFRSVUUKICAgICAgICAgICkgKwogIGFubm90YXRlKGxhYmVsID0gIlJlZmVyZW5jZSBMaW5lIChzbG9wZSA9IDEpIiwKICAgICAgICAgICAjIHggPSAxNiwKICAgICAgICAgICAjIHkgPSAzMCwKICAgICAgICAgICB4ID0gMC44MCwKICAgICAgICAgICB5ID0gMS4wNSwKICAgICAgICAgICBnZW9tID0gInRleHQiLAogICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgIGNvbG91ciA9ICJyZWQiCiAgICAgICAgICApICsKICBsYWJzKHRpdGxlID0gIlRyYXZlbERpc3RhbmNlX01pIHZzLiBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzIiwKICAgICAgIHggPSAiVHJhdmVsRGlzdGFuY2VfTWkiLAogICAgICAgeSA9ICJUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzIgogICAgICApCiMgKwojICAgZ2VvbV9qaXR0ZXIoKQoKVHJhdkRpc3RfTWlWc0NhbGMKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsRGlzdGFuY2VfTWkgJiBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzICYgVHJhdmVsRGlzdGFuY2VfTWlfTmV3LgoKR3JhcGhpbmcgdGVzdCB3aXRoIHJib2tlaC4KYGBge3J9CgpUcmF2RGlzdF9NaVZzQ2FsY19Cb2tlaCA8LSBmaWd1cmUoZGF0YSA9IHNlbGVjdChBbGxEYXlzX05ld1RyYXZlbERpc3RfMTBQY3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEaXN0TWV0aG9kCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsaW0gPSBjKDAsIDEuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGltID0gYygwLCAxLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX2xvY2F0aW9uID0gImJvdHRvbV9yaWdodCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbHlfcG9pbnRzKHggPSBUcmF2ZWxEaXN0YW5jZV9NaSwKICAgICAgICAgICAgeSA9IFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMsCiAgICAgICAgICAgIGNvbG9yID0gRGlzdE1ldGhvZCwKICAgICAgICAgICAgaG92ZXIgPSBjKFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMsIFRyYXZlbERpc3RhbmNlX01pLCBEaXN0TWV0aG9kKQogICAgICAgICAgICkgJT4lIAogIGx5X2FibGluZShhID0gMCwgYiA9IDEsIGNvbG9yID0gInJlZCIpCgpUcmF2RGlzdF9NaVZzQ2FsY19Cb2tlaAoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcuCgpDYWxjdWxhdGluZyB0aGUgbWluaW11bSBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcgdmFsdWUgYXQgZWFjaCBwZXJjZW50aWxlLgpgYGB7cn0KCnJtKFRyYXZEaXN0X01pVnNDYWxjX0Jva2VoKQpybShBbGxEYXlzX05ld1RyYXZlbERpc3RfMTBQY3QpCgoKc3VtbWFyeShzZWxlY3QoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSwKICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfSHZycywKICAgICAgICAgICAgICAgVHJhdmVsRGlzdGFuY2VfTWlfTmV3LAogICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzCiAgICAgICAgICAgICAgKQogICAgICAgKQoKc3VtbWFyeShzZWxlY3QoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgICAgICAgICAgIEJ1c0RheV9FdmVudE51bSAhPSAxCiAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pLAogICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9IdnJzLAogICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcsCiAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMKICAgICAgICAgICAgICApCiAgICAgICApCgoKVHJhdkRpc3RNaU5fTnRpbGUgPC0gYXMuZGF0YS5mcmFtZShzZWxlY3QoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdGFydFN0b3BfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ld19MYWJlbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzX0xhYmVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFBjdFJfTiA9IHBlcmNlbnRfcmFuayhBbGxEYXlzX05ld1RyYXZlbERpc3QkVHJhdmVsRGlzdGFuY2VfTWlfTmV3KSwKICAgICAgICAgIyBQY3RSX0ggPSBwZXJjZW50X3JhbmsoQWxsRGF5c19OZXdUcmF2ZWxEaXN0JFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMpLAogICAgICAgICBQY3RSX1JvdW5kX04gPSByb3VuZChQY3RSX04sIDIpCiAgICAgICAgICMgUGN0Ul9Sb3VuZF9IID0gcm91bmQoUGN0Ul9ILCAyKQogICAgICAgICkgCgojIHN0cihUcmF2RGlzdE1pTl9OdGlsZSkKIyBWaWV3KGhlYWQoVHJhdkRpc3RNaU5fTnRpbGUsIDUwMCkpCgpUcmF2RGlzdE1pTl9OdGlsZV9Sb3dzIDwtIG5yb3coVHJhdkRpc3RNaU5fTnRpbGUpCgojIFZpZXcodGFpbChUcmF2RGlzdE1pTl9OdGlsZSwgNTAwKSkKCgpUcmF2RGlzdE1pTl9QY3RpbGVzIDwtIGdyb3VwX2J5KFRyYXZEaXN0TWlOX050aWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmRfTgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgTWluVERNaUF0UGN0aWxlX04gPSBtaW4oVHJhdmVsRGlzdGFuY2VfTWlfTmV3KSwKICAgICMgTWluVERNaUF0UGN0aWxlX0ggPSBtaW4oVHJhdmVsRGlzdGFuY2VfTWlfTmV3SHZycyksCiAgICBDbnRzQXRQY3RpbGVfTiA9IHN1bSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWlfTmV3KSksCiAgICAjIENudHNBdFBjdGlsZV9IID0gc3VtKCFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzKSksCiAgICBQY3RzQXRQY3RpbGVfTiA9IENudHNBdFBjdGlsZV9OIC8gVHJhdkRpc3RNaU5fTnRpbGVfUm93cwogICAgIyBQY3RzQXRQY3RpbGVfSCA9IENudHNBdFBjdGlsZV9IIC8gVHJhdkRpc3RNaU5fTnRpbGVfUm93cwogICkgJT4lIAogIG11dGF0ZShDdW1TdW1QQXRQX04gPSBjdW1zdW0oUGN0c0F0UGN0aWxlX04pCiAgICAgICAgICMgQ3VtU3VtUEF0UF9IID0gY3Vtc3VtKFBjdHNBdFBjdGlsZV9IKQogICAgICAgICkKCiMgVmlldyhUcmF2RGlzdE1pTl9QY3RpbGVzKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzCgpDYWxjdWxhdGluZyB0aGUgbWluaW11bSBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzIHZhbHVlIGF0IGVhY2ggcGVyY2VudGlsZS4KYGBge3J9CgpUcmF2RGlzdE1pSF9OdGlsZSA8LSBhcy5kYXRhLmZyYW1lKHNlbGVjdChBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0YXJ0U3RvcF9JRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdfTGFiZWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnNfTGFiZWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVHJhdmVsRGlzdGFuY2VfTWlfTmV3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKCMgUGN0Ul9OID0gcGVyY2VudF9yYW5rKEFsbERheXNfTmV3VHJhdmVsRGlzdCRUcmF2ZWxEaXN0YW5jZV9NaV9OZXcpLAogICAgICAgICBQY3RSX0ggPSBwZXJjZW50X3JhbmsoQWxsRGF5c19OZXdUcmF2ZWxEaXN0JFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMpLAogICAgICAgICAjIFBjdFJfUm91bmRfTiA9IHJvdW5kKFBjdFJfTiwgMiksCiAgICAgICAgIFBjdFJfUm91bmRfSCA9IHJvdW5kKFBjdFJfSCwgMikKICAgICAgICApIAoKIyBzdHIoVHJhdkRpc3RNaUhfTnRpbGUpCiMgVmlldyhoZWFkKFRyYXZEaXN0TWlIX050aWxlLCA1MDApKQoKVHJhdkRpc3RNaUhfTnRpbGVfUm93cyA8LSBucm93KFRyYXZEaXN0TWlIX050aWxlKQoKIyBWaWV3KHRhaWwoVHJhdkRpc3RNaUhfTnRpbGUsIDUwMCkpCgoKVHJhdkRpc3RNaUhfUGN0aWxlcyA8LSBncm91cF9ieShUcmF2RGlzdE1pSF9OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQY3RSX1JvdW5kX0gKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHN1bW1hcmlzZSgKICAgICMgTWluVERNaUF0UGN0aWxlX04gPSBtaW4oVHJhdmVsRGlzdGFuY2VfTWlfTmV3KSwKICAgIE1pblRETWlBdFBjdGlsZV9IID0gbWluKFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMpLAogICAgIyBDbnRzQXRQY3RpbGVfTiA9IHN1bSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWlfTmV3KSksCiAgICBDbnRzQXRQY3RpbGVfSCA9IHN1bSghaXMubmEoVHJhdmVsRGlzdGFuY2VfTWlfTmV3SHZycykpLAogICAgIyBQY3RzQXRQY3RpbGVfTiA9IENudHNBdFBjdGlsZV9OIC8gVHJhdkRpc3RNaUhfTnRpbGVfUm93cywKICAgIFBjdHNBdFBjdGlsZV9IID0gQ250c0F0UGN0aWxlX0ggLyBUcmF2RGlzdE1pSF9OdGlsZV9Sb3dzCiAgKSAlPiUgCiAgbXV0YXRlKCMgQ3VtU3VtUEF0UF9OID0gY3Vtc3VtKFBjdHNBdFBjdGlsZV9OKSwKICAgICAgICAgQ3VtU3VtUEF0UF9IID0gY3Vtc3VtKFBjdHNBdFBjdGlsZV9IKQogICAgICAgICkKCiMgVmlldyhUcmF2RGlzdE1pSF9QY3RpbGVzKQoKYGBgCgoKSm9pbiBUcmF2RGlzdE1pSF9QY3RpbGVzLCBUcmF2RGlzdE1pTl9QY3RpbGVzLCBhbmQgVHJhdkRpc3RNaV9QY3RpbGVzLgoKfjExJSBvZiByaWRlcyBhcmUgc3RpbGwgc2hvd2luZyBhcyBsZXNzIHRoYW4gMC4xIG1pbGVzIG9mIFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMuCmBgYHtyfQoKcm0oVHJhdkRpc3RNaU5fTnRpbGVfUm93cywgVHJhdkRpc3RNaUhfTnRpbGVfUm93cywgVHJhdkRpc3RNaU5fTnRpbGUsIFRyYXZEaXN0TWlIX050aWxlKQoKCiMgVmlldyhUcmF2RGlzdE1pX1BjdGlsZXMpCiMgVmlldyhUcmF2RGlzdE1pTl9QY3RpbGVzKQojIFZpZXcoVHJhdkRpc3RNaUhfUGN0aWxlcykKClRyYXZEaXN0TWlfUGN0aWxlc19BbGwgPC0gaW5uZXJfam9pbih4ID0gVHJhdkRpc3RNaV9QY3RpbGVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFRyYXZEaXN0TWlOX1BjdGlsZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoIlBjdFJfUm91bmQiID0gIlBjdFJfUm91bmRfTiIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIGlubmVyX2pvaW4oeSA9IFRyYXZEaXN0TWlIX1BjdGlsZXMsCiAgICAgICAgICAgICBieSA9IGMoIlBjdFJfUm91bmQiID0gIlBjdFJfUm91bmRfSCIpCiAgICAgICAgICAgICkgJT4lIAogIHNlbGVjdChQY3RSX1JvdW5kLAogICAgICAgICBNaW5UcmF2RGlzdE1pQXRQY3RpbGUsCiAgICAgICAgIE1pblRETWlBdFBjdGlsZV9OLAogICAgICAgICBNaW5URE1pQXRQY3RpbGVfSCwKICAgICAgICAgQ250c0F0UGN0aWxlLAogICAgICAgICBDbnRzQXRQY3RpbGVfTiwKICAgICAgICAgQ250c0F0UGN0aWxlX0gsCiAgICAgICAgIFBjdHNBdFBjdGlsZSwKICAgICAgICAgUGN0c0F0UGN0aWxlX04sCiAgICAgICAgIFBjdHNBdFBjdGlsZV9ILAogICAgICAgICBDdW1TdW1QQXRQLAogICAgICAgICBDdW1TdW1QQXRQX04sCiAgICAgICAgIEN1bVN1bVBBdFBfSAogICAgICAgICApCgojIHN0cihUcmF2RGlzdE1pX1BjdGlsZXNfQWxsKQoKcm0oVHJhdkRpc3RNaV9QY3RpbGVzLCBUcmF2RGlzdE1pTl9QY3RpbGVzLFRyYXZEaXN0TWlIX1BjdGlsZXMpCgoKVmlldyhUcmF2RGlzdE1pX1BjdGlsZXNfQWxsKQpUcmF2RGlzdE1pX1BjdGlsZXNfQWxsCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFRyYXZlbERpc3RhbmNlX01pX05ldy4KCldoeSBhcmUgdGhlcmUgc3RpbGwgc29tZSBzbWFsbCBvciBsYXJnZSBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzIHZhbHVlcy4KYGBge3J9CgojIFZpZXcoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKIyAgICAgICAgICAgICAhaXMubmEoVHJhdmVsRGlzdGFuY2VfTWlfTmV3SHZycykKIyAgICAgICAgICAgICkgJT4lIAojICAgICAgICBzZWxlY3QoLVREX01pX3EyLAojICAgICAgICAgICAgICAgLVREX01pX3E5OCwKIyAgICAgICAgICAgICAgIC1URF9NaV9TU19xNSwKIyAgICAgICAgICAgICAgIC1URF9NaV9TU19xOTUsCiMgICAgICAgICAgICAgICAtVERfTWlfU1NIR19xNSwKIyAgICAgICAgICAgICAgIC1URF9NaV9TU0hHX3E5NSwKIyAgICAgICAgICAgICAgIC1URF9NaV9NZWFuLAojICAgICAgICAgICAgICAgLVREX01pX01lYW5fRiwKIyAgICAgICAgICAgICAgIC1URF9NaV9TU19NZWFuLAojICAgICAgICAgICAgICAgLVREX01pX1NTX01lYW5fRiwKIyAgICAgICAgICAgICAgIC1URF9NaV9TU0hHX01lYW4sCiMgICAgICAgICAgICAgICAtVERfTWlfU1NIR19NZWFuX0YsCiMgICAgICAgICAgICAgICAtVERfTWlfTWVkLAojICAgICAgICAgICAgICAgLVREX01pX01lZF9GLAojICAgICAgICAgICAgICAgLVREX01pX1NTX01lZCwKIyAgICAgICAgICAgICAgIC1URF9NaV9TU19NZWRfRiwKIyAgICAgICAgICAgICAgIC1URF9NaV9TU0hHX01lZCwKIyAgICAgICAgICAgICAgIC1URF9NaV9TU0hHX01lZF9GLAojICAgICAgICAgICAgICAgLVREX01pX0NudCwKIyAgICAgICAgICAgICAgIC1URF9NaV9DbnRfRiwKIyAgICAgICAgICAgICAgIC1URF9NaV9TU19DbnQsCiMgICAgICAgICAgICAgICAtVERfTWlfU1NfQ250X0YsCiMgICAgICAgICAgICAgICAtVERfTWlfU1NIR19DbnQsCiMgICAgICAgICAgICAgICAtVERfTWlfU1NIR19DbnRfRiwKIyAgICAgICAgICAgICAgIC1UVF9TZWNfcTIsCiMgICAgICAgICAgICAgICAtVFRfU2VjX3E5OCwKIyAgICAgICAgICAgICAgIC1UVF9TZWNfU1NfcTUsCiMgICAgICAgICAgICAgICAtVFRfU2VjX1NTX3E5NSwKIyAgICAgICAgICAgICAgIC1UVF9TZWNfU1NIR19xNSwKIyAgICAgICAgICAgICAgIC1UVF9TZWNfU1NIR19xOTUsCiMgICAgICAgICAgICAgICAtVFRfU2VjX01lYW4sCiMgICAgICAgICAgICAgICAtVFRfU2VjX01lYW5fRiwKIyAgICAgICAgICAgICAgIC1UVF9TZWNfU1NfTWVhbiwKIyAgICAgICAgICAgICAgIC1UVF9TZWNfU1NfTWVhbl9GLAojICAgICAgICAgICAgICAgLVRUX1NlY19TU0hHX01lYW4sCiMgICAgICAgICAgICAgICAtVFRfU2VjX1NTSEdfTWVhbl9GLAojICAgICAgICAgICAgICAgLVRUX1NlY19NZWQsCiMgICAgICAgICAgICAgICAtVFRfU2VjX01lZF9GLAojICAgICAgICAgICAgICAgLVRUX1NlY19TU19NZWQsCiMgICAgICAgICAgICAgICAtVFRfU2VjX1NTX01lZF9GLAojICAgICAgICAgICAgICAgLVRUX1NlY19TU0hHX01lZCwKIyAgICAgICAgICAgICAgIC1UVF9TZWNfU1NIR19NZWRfRiwKIyAgICAgICAgICAgICAgIC1UVF9TZWNfQ250LAojICAgICAgICAgICAgICAgLVRUX1NlY19DbnRfRiwKIyAgICAgICAgICAgICAgIC1UVF9TZWNfU1NfQ250LAojICAgICAgICAgICAgICAgLVRUX1NlY19TU19DbnRfRiwKIyAgICAgICAgICAgICAgIC1UVF9TZWNfU1NIR19DbnQsCiMgICAgICAgICAgICAgICAtVFRfU2VjX1NTSEdfQ250X0YsCiMgICAgICAgICAgICAgICAtVFRfSHJfcTIsCiMgICAgICAgICAgICAgICAtVFRfSHJfcTk4LAojICAgICAgICAgICAgICAgLVRUX0hyX1NTX3E1LAojICAgICAgICAgICAgICAgLVRUX0hyX1NTX3E5NSwKIyAgICAgICAgICAgICAgIC1UVF9Icl9TU0hHX3E1LAojICAgICAgICAgICAgICAgLVRUX0hyX1NTSEdfcTk1LAojICAgICAgICAgICAgICAgLVRUX0hyX01lYW4sCiMgICAgICAgICAgICAgICAtVFRfSHJfTWVhbl9GLAojICAgICAgICAgICAgICAgLVRUX0hyX1NTX01lYW4sCiMgICAgICAgICAgICAgICAtVFRfSHJfU1NfTWVhbl9GLAojICAgICAgICAgICAgICAgLVRUX0hyX1NTSEdfTWVhbiwKIyAgICAgICAgICAgICAgIC1UVF9Icl9TU0hHX01lYW5fRiwKIyAgICAgICAgICAgICAgIC1UVF9Icl9NZWQsCiMgICAgICAgICAgICAgICAtVFRfSHJfTWVkX0YsCiMgICAgICAgICAgICAgICAtVFRfSHJfU1NfTWVkLAojICAgICAgICAgICAgICAgLVRUX0hyX1NTX01lZF9GLAojICAgICAgICAgICAgICAgLVRUX0hyX1NTSEdfTWVkLAojICAgICAgICAgICAgICAgLVRUX0hyX1NTSEdfTWVkX0YsCiMgICAgICAgICAgICAgICAtVFRfSHJfQ250LAojICAgICAgICAgICAgICAgLVRUX0hyX0NudF9GLAojICAgICAgICAgICAgICAgLVRUX0hyX1NTX0NudCwKIyAgICAgICAgICAgICAgIC1UVF9Icl9TU19DbnRfRiwKIyAgICAgICAgICAgICAgIC1UVF9Icl9TU0hHX0NudCwKIyAgICAgICAgICAgICAgIC1UVF9Icl9TU0hHX0NudF9GCiMgICAgICAgICAgICAgICkgJT4lIAojICAgICAgICBhcnJhbmdlKFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMpICU+JSAKIyAgICAgICAgaGVhZCg1MDApCiMgICAgICkKClZpZXcoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgIWlzLm5hKFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMpCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBzZWxlY3QoLW1hdGNoZXMoIihxKDJ8NXwoOTUpfCg5OCkpKXxNZWFufE1lZHxDbnQiKQogICAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMpICU+JQogICAgICAgaGVhZCg1MDApCiAgICApCgojIGV4YW1wbGVzIG9mIHRoZSBzbWFsbGVzdCBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzIHZhbHVlcy4KVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAoUm93TnVtX09HID49IDE0MjQ0NDAgJiBSb3dOdW1fT0cgPD0gMTQyNDQ2MCkgfCAjIDE0MjQ0NTAgIC0tICBkaXJlY3Rpb24gY2hhbmdlCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDc2MzI5MiAmIFJvd051bV9PRyA8PSA3NjMzMTIpIHwgIyA3NjMzMDIgIC0tICBkaXJlY3Rpb24gY2hhbmdlCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDE2NzkwOTMgJiBSb3dOdW1fT0cgPD0gMTY3OTExMykgfCAjIDE2NzkxMDMgIC0tICBkaXJlY3Rpb24gY2hhbmdlCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDI4NjA5MTggJiBSb3dOdW1fT0cgPD0gMjg2MDkzOCkgIyAyODYwOTI4ICAtLSAgbG9va3MgY29ycmVjdAogICAgICAgICAgICkgJT4lIAogICAgICAgc2VsZWN0KC1tYXRjaGVzKCIocSgyfDV8KDk1KXwoOTgpKSl8TWVhbnxNZWR8Q250IikKICAgICAgICAgICAgICkKICAgICkKCgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgICFpcy5uYShUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzKQogICAgICAgICAgICkgJT4lIAogICAgICAgc2VsZWN0KC1tYXRjaGVzKCIocSgyfDV8KDk1KXwoOTgpKSl8TWVhbnxNZWR8Q250IikKICAgICAgICAgICAgICkgJT4lIAogICAgICAgYXJyYW5nZShkZXNjKFRyYXZlbERpc3RhbmNlX01pX05ld0h2cnMpCiAgICAgICAgICAgICAgKSAlPiUKICAgICAgIGhlYWQoNTAwKQogICAgKQoKIyBleGFtcGxlcyBvZiB0aGUgbGFyZ2VzdCBUcmF2ZWxEaXN0YW5jZV9NaV9OZXdIdnJzIHZhbHVlcy4KVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAoUm93TnVtX09HID49IDEwOTIwMDAgJiBSb3dOdW1fT0cgPD0gMTA5MjA1MCkgfCAjIDEwOTIwMzAgIC0tICBkaXJlY3Rpb24gY2hhbmdlCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDE2MDk0NjAgJiBSb3dOdW1fT0cgPD0gMTYwOTQ4MCkgfCAjIDE2MDk0NzAgIC0tIGRpcmVjdGlvbiBjaGFuZ2UgCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDUwODkwNCAmIFJvd051bV9PRyA8PSA1MDg5MjQpIHwgIyA1MDg5MTQgIC0tICBkaXJlY3Rpb24gY2hhbmdlICYgb3JpZ2luYWwgU3RvcElEIHdhcyBiYWQKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjQ3NjM0NSAmIFJvd051bV9PRyA8PSAyNDc2MzY1KSAjIDI0NzYzNTUgIC0tICBkaXJlY3Rpb24gY2hhbmdlCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBzZWxlY3QoLW1hdGNoZXMoIihxKDJ8NXwoOTUpfCg5OCkpKXxNZWFufE1lZHxDbnQiKQogICAgICAgICAgICAgKQogICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxUaW1lX0hyLgoKVmlldyhUcmF2RGlzdE1pX1BjdGlsZXMpOiA5OCUgb2YgVHJhdmVsVGltZV9IciBhcmUgYmV0d2VlbiA3IHNlY29uZHMgYW5kIDQ2NCBzZWNvbmRzICh+OCBtaW51dGVzKS4KYGBge3J9CgpUcmF2VGltZUhyX050aWxlIDwtIHNlbGVjdChBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfSHIKICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBtdXRhdGUoIyBQY3RpbGUgPSBudGlsZShBbGxEYXlzX05ld1RyYXZlbERpc3QkVHJhdmVsVGltZV9IciwgMTAwKSwKICAgICAgICAgIyBNaW5SID0gbWluX3JhbmsoQWxsRGF5c19OZXdUcmF2ZWxEaXN0JFRyYXZlbFRpbWVfSHIpLAogICAgICAgICBQY3RSID0gcGVyY2VudF9yYW5rKEFsbERheXNfTmV3VHJhdmVsRGlzdCRUcmF2ZWxUaW1lX0hyKSwKICAgICAgICAgUGN0Ul9Sb3VuZCA9IHJvdW5kKFBjdFIsIDIpCiAgICAgICAgKSAKCiMgc3RyKFRyYXZUaW1lSHJfTnRpbGUpCgpUcmF2VGltZUhyX050aWxlX1Jvd3MgPC0gbnJvdyhUcmF2VGltZUhyX050aWxlKQoKIyBWaWV3KHRhaWwoVHJhdlRpbWVIcl9OdGlsZSwgNTAwKSkKCgpUcmF2VGltZUhyX1BjdGlsZXMgPC0gZ3JvdXBfYnkoVHJhdlRpbWVIcl9OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgTWluVHJhdlRpbWVIckF0UGN0aWxlID0gbWluKFRyYXZlbFRpbWVfSHIpLAogICAgQ250c0F0UGN0aWxlID0gbigpLAogICAgUGN0c0F0UGN0aWxlID0gQ250c0F0UGN0aWxlIC8gVHJhdlRpbWVIcl9OdGlsZV9Sb3dzCiAgKSAlPiUgCiAgbXV0YXRlKEN1bVN1bVBBdFAgPSBjdW1zdW0oUGN0c0F0UGN0aWxlKSwKICAgICAgICAgTWluVHJhdlRpbWVTZWNBdFBjdGlsZSA9IE1pblRyYXZUaW1lSHJBdFBjdGlsZSAqIDM2MDAKICAgICAgICApCgpybShUcmF2VGltZUhyX050aWxlX1Jvd3MpCnJtKFRyYXZUaW1lSHJfTnRpbGUpClZpZXcoVHJhdlRpbWVIcl9QY3RpbGVzKQpUcmF2VGltZUhyX1BjdGlsZXMKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsVGltZV9Ici4KCkhpc3RvZ3JhbSBvZiBUcmF2ZWxUaW1lX1NlYy4KYGBge3J9CgpUcmF2VGltZV9TZWNfSGlzdERlbiA8LSBnZ3Bsb3QoZmlsdGVyKHNlbGVjdChBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoVHJhdmVsVGltZV9TZWMpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBUcmF2ZWxUaW1lX1NlYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gLi5kZW5zaXR5Li4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUsIGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3VyID0gImdyZXk2MCIsIHNpemUgPSAwLjIpICsKICBnZW9tX2xpbmUoc3RhdCA9ICJkZW5zaXR5IiwgY29sb3VyID0gInJlZCIpICsKICAjIHN0YXRfYmluKGJpbndpZHRoID0gNSwKICAjICAgICAgICAgIGdlb20gPSAidGV4dCIsCiAgIyAgICAgICAgICBzaXplID0gMi41LAogICMgICAgICAgICAgdmp1c3QgPSAxLjUsCiAgIyAgICAgICAgICBhZXMobGFiZWwgPSBmb3JtYXQoLi5jb3VudC4uLCBiaWcubWFyayA9ICIsIikKICAjICAgICAgICAgICAgICksCiAgIyAgICAgICAgICkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLCAxODApLCB5bGltID0gYygwLCAwLjAyKQogICAgICAgICAgICAgICAgICkgKwogICMgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIlZhcmlhdGlvbiBpbiBUcmF2ZWwgVGltZSIsCiAgICAgICB4ID0gIlRyYXZlbCBUaW1lIChzZWMpIiwKICAgICAgIHkgPSAiRGVuc2l0eSIKICAgICAgKQoKVHJhdlRpbWVfU2VjX0hpc3REZW4KCmBgYAoKCkludmVzdGlnYXRpb24gb2YgVHJhdmVsVGltZV9TZWMuCgpUcmF2ZWxUaW1lX1NlYyB2YWx1ZXMgYXJlIE5BLgpgYGB7cn0KCnN1bW1hcnkoQWxsRGF5c19OZXdUcmF2ZWxEaXN0JFRyYXZlbFRpbWVfU2VjKQoKClZpZXcoc2VsZWN0KEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgLW1hdGNoZXMoIihxKDJ8NXwoOTUpfCg5OCkpKXxNZWFufE1lZHxDbnQiKQogICAgICAgICAgICkgJT4lIAogICAgICAgZmlsdGVyKGlzLm5hKFRyYXZlbFRpbWVfU2VjKSAmCiAgICAgICAgICAgICAgICBCdXNEYXlfRXZlbnROdW0gIT0gMSAgIyBUcmF2ZWxUaW1lIHB1cnBvc2VmdWxseSBub3QgY2FsY3VsYXRlZCBoZXJlCiAgICAgICAgICAgICApCiAgICApCgojIGV4YW1wbGVzIG9mIFRyYXZlbFRpbWVfU2VjIHZhbHVlcyB0aGF0IGFyZSBOQS4gVGhlc2UgYXJlIE5BIGJlY2F1c2UgdGhlIEV2ZW50X1RpbWUgJiBEZXBhcnR1cmVfVGltZSByZWFkaW5ncyBhcmUgbm90IGFjY3VyYXRlIChpLmUuLCB0aGUgcHJldmlvdXMgRGVwYXJ0dXJlX1RpbWUgaXMgQkVGT1JFIG9yIEVRVUFMIFRPIHRoZSBjdXJyZW50IEV2ZW50X1RpbWUpLgpWaWV3KGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gOTA4MDkgJiBSb3dOdW1fT0cgPD0gOTA4MjkpIHwgIyA5MDgxOQogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSA5MDg4MSAmIFJvd051bV9PRyA8PSA5MDkwMSkgfCAjIDkwODkxCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDI1OTcwNjYgJiBSb3dOdW1fT0cgPD0gMjU5NzA4NikgfCAjIDI1OTcwNzYKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjYxMzMwNSAmIFJvd051bV9PRyA8PSAyNjEzMzI1KSAjIDI2MTMzMTUKICAgICAgICAgICApICU+JSAKICAgICAgIHNlbGVjdCgtbWF0Y2hlcygiKHEoMnw1fCg5NSl8KDk4KSkpfE1lYW58TWVkfENudCIpKQogICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxUaW1lX1NlYy4KClRyYXZlbFRpbWVfU2VjIHZhbHVlcyBhcmUgZXh0cmVtZWx5IHNtYWxsLgpgYGB7cn0KClZpZXcoc2VsZWN0KEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgLW1hdGNoZXMoIihxKDJ8NXwoOTUpfCg5OCkpKXxNZWFufE1lZHxDbnQiKQogICAgICAgICAgICkgJT4lIAogICAgICAgZmlsdGVyKCFpcy5uYShUcmF2ZWxUaW1lX1NlYykKICAgICAgICAgICAgICkgJT4lIAogICAgICAgYXJyYW5nZShUcmF2ZWxUaW1lX1NlYywKICAgICAgICAgICAgICAgZGVzYyhTcGVlZEF2Z19NcGhfTmV3SHZycykKICAgICAgICAgICAgICApICU+JQogICAgICAgaGVhZCg1MDApCiAgICApCgojIGV4YW1wbGVzIHdoZXJlIFRyYXZlbFRpbWVfU2VjIGlzIHNtYWxsICgxIHNlYykgYW5kIFNwZWVkQXZnX01waF9OZXdIdnJzIGlzIGxhcmdlLgpWaWV3KHNlbGVjdChBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgIC1tYXRjaGVzKCIocSgyfDV8KDk1KXwoOTgpKSl8TWVhbnxNZWR8Q250IikKICAgICAgICAgICApICU+JSAKICAgICAgIGZpbHRlcigoUm93TnVtX09HID49IDIyMTczNTMgJiBSb3dOdW1fT0cgPD0gMjIxNzM3MykgfCAjIDIyMTczNjMKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMzA5MDMyMSAmIFJvd051bV9PRyA8PSAzMDkwMzQxKSB8ICMgMzA5MDMzMQogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSA4MDc2NCAmIFJvd051bV9PRyA8PSA4MDc4NCkgfCAjIDgwNzc0CiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDMzODQwICYgUm93TnVtX09HIDw9IDMzODYwKSAjIDMzODUwCiAgICAgICAgICAgKQogICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBUcmF2ZWxUaW1lX1NlYy4KClRyYXZlbFRpbWVfU2VjIHZhbHVlcyBhcmUgZXh0cmVtZWx5IGxhcmdlLgpgYGB7cn0KClZpZXcoc2VsZWN0KEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgLW1hdGNoZXMoIihxKDJ8NXwoOTUpfCg5OCkpKXxNZWFufE1lZHxDbnQiKQogICAgICAgICAgICkgJT4lIAogICAgICAgZmlsdGVyKCFpcy5uYShUcmF2ZWxUaW1lX1NlYykKICAgICAgICAgICAgICkgJT4lIAogICAgICAgYXJyYW5nZShkZXNjKFRyYXZlbFRpbWVfU2VjKSwKICAgICAgICAgICAgICAgU3BlZWRBdmdfTXBoX05ld0h2cnMKICAgICAgICAgICAgICApICU+JQogICAgICAgaGVhZCg1MDApCiAgICApCgojIGV4YW1wbGVzIHdoZXJlIFRyYXZlbFRpbWVfU2VjIGlzIGxhcmdlIGFuZCBTcGVlZEF2Z19NcGhfTmV3SHZycyBpcyBzbWFsbC4KVmlldyhzZWxlY3QoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAtbWF0Y2hlcygiKHEoMnw1fCg5NSl8KDk4KSkpfE1lYW58TWVkfENudCIpCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBmaWx0ZXIoKFJvd051bV9PRyA+PSAxMDA3NzAzICYgUm93TnVtX09HIDw9IDEwMDc3MjMpIHwgIyAxMDA3NzEzCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDIzNzM1NjQgJiBSb3dOdW1fT0cgPD0gMjM3MzU4NCkgfCAjIDIzNzM1NzQKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gODY0Mzc5ICYgUm93TnVtX09HIDw9IDg2NDM5OSkgfCAjIDg2NDM4OQogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAyNTcwMDYwICYgUm93TnVtX09HIDw9IDI1NzAwODApICMgMjU3MDA3MAogICAgICAgICAgICkKICAgICkKCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFRyYXZlbFRpbWVfU2VjLgoKQXJlIGxhcmdlIFRyYXZlbFRpbWVfU2VjIHZhbHVlcyByZWxhdGVkIHRvIFJvdXRlQ2hhbmdlcz8gTG9va3MgbGlrZWx5LiBXaGVuIHRoZSBCdXMgaW52b2x2ZXMgYSBSb3V0ZSAiY2hhbmdlIiwgdGhlcmUgaXMgYWxtb3N0IHR3aWNlIGFzIGxpa2VseSB0byBiZSBhIGNhc2Ugb2YgYW4gb3V0bGllciBUcmF2ZWxUaW1lX1NlYyB2YWx1ZSAob24gdGhlIGhpZ2ggc2lkZSkuCmBgYHtyfQoKVFRMYXJnZVJ0ZUNobmcgPC0gc2VsZWN0KEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgIC1tYXRjaGVzKCIocSgyfDV8KDk1KXwoOTgpKSl8TWVhbnxNZWR8Q250IikKICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFRUX091dCA9IGZhY3RvcihpZmVsc2UoVHJhdmVsVGltZV9TZWMgPiA0NjQsICAjIHRoaXMgaXMgdGhlIDk5dGggcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdXRsaWVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9ybWFsIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgKQoKIyBzdHIoVFRMYXJnZVJ0ZUNobmcpCgoKVFRMYXJnZVJ0ZUNobmdfQ250cyA8LSBncm91cF9ieShUVExhcmdlUnRlQ2huZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSdGVDaGFuZ2UyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX091dAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKENudHMgPSBuKCkKICAgICAgICAgICApCgpUVExhcmdlUnRlQ2huZ19TcHJlYWQgPC0gYXMuZGF0YS5mcmFtZShzcHJlYWQoVFRMYXJnZVJ0ZUNobmdfQ250cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX091dCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENudHMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lCiAgc2VsZWN0KC1SdGVDaGFuZ2UyKQoKcm93Lm5hbWVzKFRUTGFyZ2VSdGVDaG5nX1NwcmVhZCkgPC0gYygiQ2hhbmdlIiwgIlNhbWUiKQojIHN0cihUVExhcmdlUnRlQ2huZ19TcHJlYWQpCgoKIyBXaGVuIHRoZSBCdXMgaW52b2x2ZXMgYSBSb3V0ZSAiY2hhbmdlIiwgdGhlcmUgaXMgYWxtb3N0IHR3aWNlIGFzIGxpa2VseSB0byBiZSBhIGNhc2Ugb2YgYW4gb3V0bGllciBUcmF2ZWxUaW1lX1NlYyB2YWx1ZS4KVFRMYXJnZVJ0ZUNobmdfU3ByZWFkCnByb3AudGFibGUoYXMudGFibGUoYXMubWF0cml4KFRUTGFyZ2VSdGVDaG5nX1NwcmVhZCkKICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgMQogICAgICAgICAgKQoKcHJvcC50YWJsZShhcy50YWJsZShhcy5tYXRyaXgoVFRMYXJnZVJ0ZUNobmdfU3ByZWFkKQogICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAyCiAgICAgICAgICApCgojIHJtKFRUTGFyZ2VSdGVDaG5nLCBUVExhcmdlUnRlQ2huZ19TcHJlYWQpCiAgICAgICAgIAoKVmlldyhmaWx0ZXIoVFRMYXJnZVJ0ZUNobmcsCiAgICAgICAgICAgICFpcy5uYShUcmF2ZWxUaW1lX1NlYykgJgogICAgICAgICAgICAgIFJ0ZUNoYW5nZTIgPT0gIlNhbWUiCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKGRlc2MoVHJhdmVsVGltZV9TZWMpLAogICAgICAgICAgICAgICBTcGVlZEF2Z19NcGhfTmV3SHZycwogICAgICAgICAgICAgICkgJT4lCiAgICAgICBoZWFkKDUwMCkKICAgICkKCgojIGV4YW1wbGVzIHdoZXJlIFRyYXZlbFRpbWVfU2VjIGlzIGxhcmdlIGFuZCBTcGVlZEF2Z19NcGhfTmV3SHZycyBpcyBzbWFsbC4KVmlldyhmaWx0ZXIoVFRMYXJnZVJ0ZUNobmcsCiAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjI1MDI5MCAmIFJvd051bV9PRyA8PSAyMjUwMzEwKSB8ICMgMjI1MDMwMAogICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gODY3NzE3ICYgUm93TnVtX09HIDw9IDg2NzczNykgfCAjIDg2NzcyNwogICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gODY0Mzc5ICYgUm93TnVtX09HIDw9IDg2NDM5OSkgfCAjIDg2NDM4OQogICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gODA4Mzk1ICYgUm93TnVtX09HIDw9IDgwODQxNSkgIyA4MDg0MDUKICAgICAgICAgICApCiAgICApCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFRyYXZlbFRpbWVfU2VjLgoKSWYgVHJhdmVsVGltZV9TZWMgaXMgYmVsb3cgdGhlIDV0aCBwZXJjZW50aWxlIGZvciB0aGF0IFN0YXJ0U3RvcF9JRCwgb3IgaWYgVHJhdmVsVGltZV9TZWMgaXMgYWJvdmUgdGhlIDk1dGggcGVyY2VudGlsZSBmb3IgdGhhdCBTdGFydFN0b3BfSUQsICBjb25zaWRlciB0aGlzIGFuIG91dGxpZXIuICBJbiB0aGlzIGNhc2UsIHJlcGxhY2UgdGhlIHZhbHVlIHdpdGggdGhlIG1lYW4gZm9yIHRoYXQgU3RhcnRTdG9wX0lEIGFuZCBIb3VyR3JvdXAgKFRUX1NlY19TU0hHX01lYW5fRiksIG9yIGlmIHRoZXJlIGFyZSBub3QgZW5vdWdoIHZhbHVlcyBhdCB0aGUgSG91ckdyb3VwIGxldmVsLCByZXBsYWNlIGl0IHdpdGggdGhlIG1lYW4gZm9yIHRoYXQgU3RhcnRTdG9wX0lELgpgYGB7cn0KCnJtKFRUTGFyZ2VSdGVDaG5nLCBUVExhcmdlUnRlQ2huZ19DbnRzLCBUVExhcmdlUnRlQ2huZ19TcHJlYWQpCgoKTmV3VHJhdlRpbWUgPC0gbXV0YXRlKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19OZXcgPSBpZmVsc2UoIWlzLm5hKFRyYXZlbFRpbWVfU2VjKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKFRyYXZlbFRpbWVfU2VjIDwgVFRfU2VjX1NTSEdfcTUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjID4gVFRfU2VjX1NTSEdfcTk1CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTSEdfQ250X0YgPj0gMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19TU0hHX01lYW5fRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoIWlzLm5hKFRyYXZlbFRpbWVfU2VjKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKFRyYXZlbFRpbWVfU2VjIDwgVFRfU2VjX1NTSEdfcTUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjID4gVFRfU2VjX1NTSEdfcTk1CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTSEdfQ250X0YgPCAyMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTX0NudF9GID49IDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfTWVhbl9GLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSghaXMubmEoVHJhdmVsVGltZV9TZWMpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoVHJhdmVsVGltZV9TZWMgPCBUVF9TZWNfU1NIR19xNSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMgPiBUVF9TZWNfU1NIR19xOTUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfQ250X0YgPCAyMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTX0NudCA+PSAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTX01lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKCFpcy5uYShUcmF2ZWxUaW1lX1NlYykgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChUcmF2ZWxUaW1lX1NlYyA8IFRUX1NlY19TU0hHX3E1IHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYyA+IFRUX1NlY19TU0hHX3E5NQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19TU19DbnRfRiA8IDIwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfQ250IDwgMjAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJ0ZUNoYW5nZTIgPT0gIkNoYW5nZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpKSksCiAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19OZXdfTGFiZWwgPSAKICAgICAgICAgICBmYWN0b3IoaWZlbHNlKCFpcy5uYShUcmF2ZWxUaW1lX1NlYykgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAoVHJhdmVsVGltZV9TZWMgPCBUVF9TZWNfU1NIR19xNSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjID4gVFRfU2VjX1NTSEdfcTk1CiAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NIR19DbnRfRiA+PSAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICJUVF9TZWNfU1NIR19NZWFuX0YiLAogICAgICAgICAgICAgICAgICBpZmVsc2UoIWlzLm5hKFRyYXZlbFRpbWVfU2VjKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIChUcmF2ZWxUaW1lX1NlYyA8IFRUX1NlY19TU0hHX3E1IHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMgPiBUVF9TZWNfU1NIR19xOTUKICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19TU0hHX0NudF9GIDwgMjAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfQ250X0YgPj0gMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAiVFRfU2VjX1NTX01lYW5fRiIsCiAgICAgICAgICAgICAgICAgIGlmZWxzZSghaXMubmEoVHJhdmVsVGltZV9TZWMpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgKFRyYXZlbFRpbWVfU2VjIDwgVFRfU2VjX1NTSEdfcTUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYyA+IFRUX1NlY19TU0hHX3E5NQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFRUX1NlY19TU19DbnRfRiA8IDIwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTX0NudCA+PSAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICJUVF9TZWNfU1NfTWVhbiIsCiAgICAgICAgICAgICAgICAgIGlmZWxzZSghaXMubmEoVHJhdmVsVGltZV9TZWMpICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgKFRyYXZlbFRpbWVfU2VjIDwgVFRfU2VjX1NTSEdfcTUgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYyA+IFRUX1NlY19TU0hHX3E5NQogICAgICAgICAgICAgICAgICAgICAgICAgICApICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgVFRfU2VjX1NTX0NudF9GIDwgMjAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBUVF9TZWNfU1NfQ250IDwgMjAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBSdGVDaGFuZ2UyID09ICJDaGFuZ2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAiVHJhdmVsVGltZV9TZWMiCiAgICAgICAgICAgICAgICAgICAgICAgICkpKSkKICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgVFRfSHJfTmV3ID0gVFRfU2VjX05ldyAvICg2MCAqIDYwKQogICAgICAgICAgICkKCgpkaW0oQWxsRGF5c19OZXdUcmF2ZWxEaXN0KQpkaW0oTmV3VHJhdlRpbWUpCnJtKEFsbERheXNfTmV3VHJhdmVsRGlzdCkKCnN1bW1hcnkoc2VsZWN0KE5ld1RyYXZUaW1lLAogICAgICAgICAgIC1tYXRjaGVzKCIocSgyfDV8KDk1KXwoOTgpKSl8TWVhbnxNZWR8Q250IikKICAgICAgICAgICkKICAgKQoKc3RyKHNlbGVjdChOZXdUcmF2VGltZSwKICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYywKICAgICAgICAgICBUVF9TZWNfTmV3LAogICAgICAgICAgIFRUX1NlY19OZXdfTGFiZWwsCiAgICAgICAgICAgVFRfSHJfTmV3CiAgICAgICAgICApCiAgICkKCgpzdW1tYXJ5KHNlbGVjdChOZXdUcmF2VGltZSwKICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMsCiAgICAgICAgICAgICAgIFRUX1NlY19OZXcsCiAgICAgICAgICAgICAgIFRUX1NlY19OZXdfTGFiZWwsCiAgICAgICAgICAgICAgIFRUX0hyX05ldwogICAgICAgICAgICAgICkKICAgICAgICkKCmBgYAoKClRlc3QgaW52ZXN0aWdhdGlvbiBvZiBqdXN0IHRoZSBYMiBSb3V0ZS4gQm94IHBsb3RzIGZvciB0aW1lIGJldHdlZW4gYnVzIGFycml2YWxzIChieSBIb3VyR3JvdXApLgpgYGB7cn0KClZpZXcoaGVhZChzZWxlY3QoTmV3VHJhdlRpbWUsCiAgICAgICAgICAgICAgICAgLW1hdGNoZXMoIihxKDJ8NXwoOTUpfCg5OCkpKXxNZWFufE1lZHxDbnQiKQogICAgICAgICAgICAgICAgKQogICAgICAgICApCiAgICApCgpYMiA8LSBzZWxlY3QoTmV3VHJhdlRpbWUsCiAgICAgICAgICAgICAtbWF0Y2hlcygiKHEoMnw1fCg5NSl8KDk4KSkpfE1lYW58TWVkfENudCIpCiAgICAgICAgICAgICkgJT4lIAogIGZpbHRlcihSb3V0ZSA9PSAiWDIiKQoKc3RyKFgyKQoKVmlldyhoZWFkKGFycmFuZ2UoWDIsCiAgICAgICAgICAgICAgICAgIEJ1c19JRCwKICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZQogICAgICAgICAgICAgICAgICksCiAgICAgICAgICA1MDAKICAgICAgICAgKQogICAgKQoKWDJfQnlTdG9wIDwtIGdyb3VwX2J5KFgyLAogICAgICAgICAgICAgICAgICAgICAgU3RvcElEX0NsZWFuCiAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIGFycmFuZ2UoU3RvcElEX0NsZWFuLAogICAgICAgICAgRXZlbnRfVGltZSkgJT4lIAogIG11dGF0ZShFdmVudF9UaW1lX0wxID0gbGFnKEV2ZW50X1RpbWUpLAogICAgICAgICBUaW1lVG9FdmVudF9TZWMgPSBhcy5udW1lcmljKEV2ZW50X1RpbWUgLSBFdmVudF9UaW1lX0wxKSwKICAgICAgICAgVGltZVRvRXZlbnRfTWluID0gVGltZVRvRXZlbnRfU2VjIC8gNjAKICAgICAgICApCgpWaWV3KGhlYWQoWDJfQnlTdG9wLCA1MDApKQoKCiMgQ291bnRfVmFsdWVzIGlzIG5lZWRlZCB0byBkaXNwbGF5IHRoZSBtZWRpYW5zIG9uIHRoZSBib3ggcGxvdHMKQ291bnRfVmFsdWVzIDwtIGRkcGx5KGFzLmRhdGEuZnJhbWUoWDJfQnlTdG9wKSwKICAgICAgICAgICAgICAgICAgICAgIC4oRXZlbnRfVGltZV9Ickdyb3VwKSwKICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSwKICAgICAgICAgICAgICAgICAgICAgIFZhbHVlX0NvdW50cyA9IG1lZGlhbihUaW1lVG9FdmVudF9NaW4sIG5hLnJtID0gVFJVRSkKICAgICAgICAgICAgICAgICAgICAgKQoKVGltZUJ0d0V2ZW50c19YMl9Cb3hQbG90IDwtIGdncGxvdChzZWxlY3QoYXMuZGF0YS5mcmFtZShYMl9CeVN0b3ApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaW1lVG9FdmVudF9NaW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfSHJHcm91cAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGZhY3RvcihFdmVudF9UaW1lX0hyR3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaW1lVG9FdmVudF9NaW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBmYWN0b3IoRXZlbnRfVGltZV9Ickdyb3VwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgKyAKICBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9InJlZCIsIG5vdGNoPVRSVUUsIG5hLnJtID0gVFJVRSkgKwogIGdlb21fdGV4dChkYXRhID0gQ291bnRfVmFsdWVzLAogICAgICAgICAgICBhZXMoeSA9IFZhbHVlX0NvdW50cywKICAgICAgICAgICAgICAgIGxhYmVsID0gZm9ybWF0KHJvdW5kKFZhbHVlX0NvdW50cywgZGlnaXRzID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc21hbGwgPSAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNQogICAgICAgICAgICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1KSkgKwogIGNvb3JkX2NhcnRlc2lhbigjIHhsaW0gPSBjKDAsIDE4MCksCiAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDAsIDEyMCkKICAgICAgICAgICAgICAgICApICsKICBsYWJzKHRpdGxlID0gIkhvdyBPZnRlbiBhbiBYMiBBcnJpdmVzIGF0IGEgR2l2ZW4gU3RvcCIsCiAgICAgICB4ID0gIkhvdXIgR3JvdXAiLAogICAgICAgeSA9ICJUaW1lIEJldHdlZW4gQnVzc2VzIChtaW4pIgogICAgICApCgpUaW1lQnR3RXZlbnRzX1gyX0JveFBsb3QKCmBgYAoKClRlc3QgaW52ZXN0aWdhdGlvbiBvZiBqdXN0IHRoZSBYMiBSb3V0ZS4gVmlvbGluIHBsb3RzIGZvciB0aW1lIGJldHdlZW4gYnVzIGFycml2YWxzIChieSBIb3VyIEdyb3VwKS4KYGBge3J9CgpUaW1lQnR3RXZlbnRzX1gyX1Zpb2xpblBsb3QgPC0gZ2dwbG90KHNlbGVjdChhcy5kYXRhLmZyYW1lKFgyX0J5U3RvcCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpbWVUb0V2ZW50X01pbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9Ickdyb3VwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGZhY3RvcihFdmVudF9UaW1lX0hyR3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaW1lVG9FdmVudF9NaW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBmYWN0b3IoRXZlbnRfVGltZV9Ickdyb3VwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgKyAKICBnZW9tX3Zpb2xpbihkcmF3X3F1YW50aWxlcyA9IGMoMC4yNSwgMC41LCAwLjc1KSwKICAgICAgICAgICAgICB0cmltID0gVFJVRSwKICAgICAgICAgICAgICBzY2FsZSA9ICJjb3VudCIsCiAgICAgICAgICAgICAgbmEucm0gPSBUUlVFLAogICAgICAgICAgICAgIHNob3cubGVnZW5kID0gTkEsCiAgICAgICAgICAgICAgaW5oZXJpdC5hZXMgPSBUUlVFCiAgICAgICAgICAgICApICsKICBnZW9tX3RleHQoZGF0YSA9IENvdW50X1ZhbHVlcywKICAgICAgICAgICAgYWVzKHkgPSBWYWx1ZV9Db3VudHMsCiAgICAgICAgICAgICAgICBsYWJlbCA9IGZvcm1hdChyb3VuZChWYWx1ZV9Db3VudHMsIGRpZ2l0cyA9IDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnNtYWxsID0gMQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIHNpemUgPSAyLjUsCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNQogICAgICAgICAgICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1KSkgKwogIGNvb3JkX2NhcnRlc2lhbigjIHhsaW0gPSBjKDAsIDE4MCksCiAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDAsIDgwKQogICAgICAgICAgICAgICAgICkgKwogIGxhYnModGl0bGUgPSAiSG93IE9mdGVuIGFuIFgyIEFycml2ZXMgYXQgYSBHaXZlbiBTdG9wIiwKICAgICAgIHggPSAiSG91ciBHcm91cCIsCiAgICAgICB5ID0gIlRpbWUgQmV0d2VlbiBCdXNzZXMgKG1pbikiCiAgICAgICkKClRpbWVCdHdFdmVudHNfWDJfVmlvbGluUGxvdAoKYGBgCgoKVGVzdCBpbnZlc3RpZ2F0aW9uIG9mIGp1c3QgdGhlIFgyIFJvdXRlLiBCb3ggcGxvdHMgZm9yIHRpbWUgYmV0d2VlbiBidXMgYXJyaXZhbHMgKGJ5IFppcCBDb2RlKS4KYGBge3J9CgojIENvdW50X1ZhbHVlcyBpcyBuZWVkZWQgdG8gZGlzcGxheSB0aGUgbWVkaWFucyBvbiB0aGUgYm94IHBsb3RzCkNvdW50X1ZhbHVlc196IDwtIGRkcGx5KGFzLmRhdGEuZnJhbWUoWDJfQnlTdG9wKSwKICAgICAgICAgICAgICAgICAgICAgICAgLihTdG9wX1ppcCksCiAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSwKICAgICAgICAgICAgICAgICAgICAgICAgVmFsdWVfQ291bnRzID0gbWVkaWFuKFRpbWVUb0V2ZW50X01pbiwgbmEucm0gPSBUUlVFKQogICAgICAgICAgICAgICAgICAgICAgICkKClRpbWVCdHdFdmVudHNfWDJfQm94UGxvdF96IDwtIGdncGxvdChzZWxlY3QoYXMuZGF0YS5mcmFtZShYMl9CeVN0b3ApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpbWVUb0V2ZW50X01pbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdG9wX1ppcAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhmYWN0b3IoU3RvcF9aaXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpbWVUb0V2ZW50X01pbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZmFjdG9yKFN0b3BfWmlwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsgCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJyZWQiLCBub3RjaD1UUlVFLCBuYS5ybSA9IFRSVUUpICsKICBnZW9tX3RleHQoZGF0YSA9IENvdW50X1ZhbHVlc196LAogICAgICAgICAgICBhZXMoeSA9IFZhbHVlX0NvdW50cywKICAgICAgICAgICAgICAgIGxhYmVsID0gZm9ybWF0KHJvdW5kKFZhbHVlX0NvdW50cywgZGlnaXRzID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc21hbGwgPSAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNQogICAgICAgICAgICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1KSkgKwogIGNvb3JkX2NhcnRlc2lhbigjIHhsaW0gPSBjKDAsIDE4MCksCiAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDAsIDEwMCkKICAgICAgICAgICAgICAgICApICsKICBsYWJzKHRpdGxlID0gIkhvdyBPZnRlbiBhbiBYMiBBcnJpdmVzIGF0IGEgR2l2ZW4gU3RvcCIsCiAgICAgICB4ID0gIlppcCBDb2RlIG9mIERlc3RpbmF0aW9uIiwKICAgICAgIHkgPSAiVGltZSBCZXR3ZWVuIEJ1c3NlcyAobWluKSIKICAgICAgKQoKVGltZUJ0d0V2ZW50c19YMl9Cb3hQbG90X3oKCmBgYAoKClRlc3QgaW52ZXN0aWdhdGlvbiBvZiBqdXN0IHRoZSBYMiBSb3V0ZS4gVmlvbGluIHBsb3RzIGZvciB0aW1lIGJldHdlZW4gYnVzIGFycml2YWxzIChieSBaaXAgQ29kZSkuCmBgYHtyfQoKVGltZUJ0d0V2ZW50c19YMl9WaW9saW5QbG90X3ogPC0gZ2dwbG90KHNlbGVjdChhcy5kYXRhLmZyYW1lKFgyX0J5U3RvcCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGltZVRvRXZlbnRfTWluLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BfWmlwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhmYWN0b3IoU3RvcF9aaXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpbWVUb0V2ZW50X01pbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZmFjdG9yKFN0b3BfWmlwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsgCiAgZ2VvbV92aW9saW4oZHJhd19xdWFudGlsZXMgPSBjKDAuMjUsIDAuNSwgMC43NSksCiAgICAgICAgICAgICAgdHJpbSA9IFRSVUUsCiAgICAgICAgICAgICAgc2NhbGUgPSAiY291bnQiLAogICAgICAgICAgICAgIG5hLnJtID0gVFJVRSwKICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IE5BLAogICAgICAgICAgICAgIGluaGVyaXQuYWVzID0gVFJVRQogICAgICAgICAgICAgKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBDb3VudF9WYWx1ZXNfeiwKICAgICAgICAgICAgYWVzKHkgPSBWYWx1ZV9Db3VudHMsCiAgICAgICAgICAgICAgICBsYWJlbCA9IGZvcm1hdChyb3VuZChWYWx1ZV9Db3VudHMsIGRpZ2l0cyA9IDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnNtYWxsID0gMQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIHNpemUgPSAyLjUsCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNQogICAgICAgICAgICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1KSkgKwogIGNvb3JkX2NhcnRlc2lhbigjIHhsaW0gPSBjKDAsIDE4MCksCiAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDAsIDYwKQogICAgICAgICAgICAgICAgICkgKwogIGxhYnModGl0bGUgPSAiSG93IE9mdGVuIGFuIFgyIEFycml2ZXMgYXQgYSBHaXZlbiBTdG9wIiwKICAgICAgIHggPSAiWmlwIENvZGUgb2YgRGVzdGluYXRpb24iLAogICAgICAgeSA9ICJUaW1lIEJldHdlZW4gQnVzc2VzIChtaW4pIgogICAgICApCgpUaW1lQnR3RXZlbnRzX1gyX1Zpb2xpblBsb3RfegoKYGBgCgoKV2FpdGluZyB0aW1lIGFuYWx5c2VzLgoKTXVuZ2luZyBhbmQgc2FtcGxpbmcgZGF0YSB0byBnbyBmcm9tIHRpbWUgYmV0ZWVuIGJ1c2VzIHRvICJhdmVyYWdlIiB3YWl0aW5nIHRpbWUuCgpGaXJzdCwgZ2V0IHRoZSBtYXggYW5kIG1pbiB0aW1lcyBvZiBidXMgc3RvcHMgKGVhY2ggZGF5LCBhbmQgZm9yIGVhY2ggcm91dGUpLgpgYGB7cn0KClJvdXRlTWluTWF4IDwtIGdyb3VwX2J5KE5ld1RyYXZUaW1lLAogICAgICAgICAgICAgICAgICAgICAgICBSb3V0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9EYXRlCiAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKE1pblRpbWUgPSBtaW4oRXZlbnRfVGltZSksCiAgICAgICAgICAgIE1heFRpbWUgPSBtYXgoRXZlbnRfVGltZSkKICAgICAgICAgICApCgpzdHIoUm91dGVNaW5NYXgpClZpZXcoUm91dGVNaW5NYXgpCgpgYGAKCgpXYWl0aW5nIHRpbWUgYW5hbHlzZXMuCgpNdW5naW5nIGFuZCBzYW1wbGluZyBkYXRhIHRvIGdvIGZyb20gdGltZSBiZXRlZW4gYnVzZXMgdG8gImF2ZXJhZ2UiIHdhaXRpbmcgdGltZS4KCihQdWxscyBoZXJlIGFyZSBkb25lIGJ5IGRheSwgYXMgdGhlIGRhdGEgYXJlIHRvbyBsYXJnZSB0byBkbyBhdCBvbmNlLikKYGBge3J9CgojIFZpZXcoaGVhZChOZXdUcmF2VGltZSwgNTAwKSkKCiMgRm9yIGVhY2ggcmVjb3JkLCBjcmVhdGUgYSByYW5kb20gZGF0ZXRpbWUgYmV0d2VlbiB0aGUgZmlyc3QgYW5kIGxhc3Qgc3RvcCBmb3IgdGhhdCBidXMgcm91dGUgKG9uIHRoYXQgZGF5KS4KZm9yKGkgaW4gMzo3KXsKCnNldC5zZWVkKDEyMzQ1Njc4OSkKU2FtcCA8LSBzZWxlY3QoTmV3VHJhdlRpbWUsCiAgICAgICAgICAgICAgIFJvd051bV9PRywKICAgICAgICAgICAgICAgUm91dGUsCiAgICAgICAgICAgICAgICMgUm91dGVHcm91cCwKICAgICAgICAgICAgICAgRXZlbnRfVGltZV9EYXRlLAogICAgICAgICAgICAgICBTdG9wSURfQ2xlYW4sCiAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKCJFdmVudCIpCiAgICAgICAgICAgICAgKSAlPiUgCiAgZmlsdGVyKEV2ZW50X1RpbWVfRGF0ZSA9PSBpKSAlPiUgICMgbmVlZGVkIHRvIGRvIHRoaXMgZWFjaCBkYXkgKDMtNykgYmVjYXVzZSB0aGUgY29tcGxldGUgZmlsZSB3YXMgdG9vIGxhcmdlIHRvIGRvIGF0IG9uY2UKICBsZWZ0X2pvaW4oUm91dGVNaW5NYXgsCiAgICAgICAgICAgIGJ5ID0gYygiUm91dGUiID0gIlJvdXRlIiwKICAgICAgICAgICAgICAgICAgICJFdmVudF9UaW1lX0RhdGUiID0gIkV2ZW50X1RpbWVfRGF0ZSIKICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICkgJT4lIAogIG11dGF0ZShTYW1wVGltZSA9IGFzX2RhdGV0aW1lKHJ1bmlmKG5yb3coLiksICMyMDAwMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluID0gTWluVGltZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXggPSBNYXhUaW1lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR6ID0gIkFtZXJpY2EvTmV3X1lvcmsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgKSAlPiUgCiAgYXJyYW5nZShSb3V0ZSwKICAgICAgICAgIFN0b3BJRF9DbGVhbiwKICAgICAgICAgIEV2ZW50X1RpbWUKICAgICAgICAgKSAKCiMgc3RyKFNhbXApCiMgVmlldyhoZWFkKFNhbXAsIDUwMCkpCiMgCiMgVmlldygKIyBncm91cF9ieShTYW1wLAojICAgICAgICAgIFJvd051bV9PRwojICAgICAgICAgKSAlPiUKIyAgIHN1bW1hcmlzZShDbnRfTnVtID0gbigpLAojICAgICAgICAgICAgIENudF9QY3QgPSAxMDAgKiBDbnRfTnVtIC8gbnJvdyhTYW1wKQojICAgICAgICAgICAgKSAlPiUKIyAgIGFycmFuZ2UoZGVzYyhDbnRfTnVtKSkKIyApCgoKIyBGb3IgZWFjaCBSb3V0ZSBhbmQgU3RvcElEIGNvbWJpbmF0aW9uLCBnZXQgYWxsIHRoZSBFdmVudF9UaW1lIHZhbHVlcyB0aGF0IGFyZSBhZnRlciB0aGUgU2FtcFRpbWUgdmFsdWUuCiMgZXN0aW1hdGluZyBhcHByb3ggMmhycyBvZiBydW50aW1lIGZvciBhbGwgMi44bSByZWNvcmRzClRlc3RpbmdfQSA8LSBzcWxkZigiICAgU2VsZWN0ICAgICAgICAgICAgICAgdDEuKgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICx0Mi5FdmVudF9UaW1lICAgICAgICAgICAgIGFzIE5leHRCdXMKICAgICAgICAgICAgICAgICAgICAgICAgRnJvbSAgICAgICAgICAgICAgICAgU2FtcCAgICAgICAgICAgICAgICAgICAgICBhcyB0MQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIElubmVyIEpvaW4gICAgICBTYW1wICAgICAgICAgICAgICAgICAgICAgIGFzIHQyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT24gICAgICAgICAgICAgIHQxLlJvdXRlID0gdDIuUm91dGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbmQgICAgICAgICAgICAgdDEuU3RvcElEX0NsZWFuID0gdDIuU3RvcElEX0NsZWFuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQW5kICAgICAgICAgICAgIHQyLkV2ZW50X1RpbWUgPiB0MS5TYW1wVGltZQogICAgICAgICAgICAgICAgICAgICAgICBPcmRlciBCeSAgICAgICAgICAgICB0MS5Sb3V0ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICx0MS5TdG9wSURfQ2xlYW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsdDEuRXZlbnRfVGltZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICx0Mi5FdmVudF9UaW1lCiAgICAgICAgICAgICAgICAgICIKICAgICAgICAgICAgICAgICApICU+JSAKICBtdXRhdGUoTkIgPSBhc19kYXRldGltZShOZXh0QnVzLAogICAgICAgICAgICAgICAgICAgICAgICAgIHR6ID0gIkFtZXJpY2EvTmV3X1lvcmsiCiAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgKQoKIyBzdHIoVGVzdGluZ19BKQojIFZpZXcoaGVhZChUZXN0aW5nX0EsIDUwMCkpCiMgVmlldyhoZWFkKFNhbXAsIDUwMCkpCgoKIyBGaWx0ZXIgdGhlIGRhdGFmcmFtZSB0byBvbmx5IGluY2x1ZGUgdGhlIGJ1cyBhcnJpdmFsIGF0IFN0b3BJRCB0aGF0IGlzIHRoZSBuZXh0IHRvIGNvbWUgYWZ0ZXIgdGhlIFNhbXBUaW1lLgojIGVzdGltYXRpbmcgYXBwcm94IDIwbWluIG9mIHJ1bnRpbWUgZm9yIGFsbCAyLjhtIHJlY29yZHMKVGVzdGluZyA8LSBzZWxlY3QoVGVzdGluZ19BLAogICAgICAgICAgICAgICAgICAtTmV4dEJ1cwogICAgICAgICAgICAgICAgICkgJT4lIAogIGdyb3VwX2J5KFJvd051bV9PRykgJT4lIAogIGZpbHRlcihOQiA9PSBtaW4oTkIpCiAgICAgICAgKSAlPiUgCiAgYXJyYW5nZShSb3V0ZSwKICAgICAgICAgIFN0b3BJRF9DbGVhbiwKICAgICAgICAgIEV2ZW50X1RpbWUKICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFdhaXRUaW1lX01pbiA9IGFzLm51bWVyaWMoTkIgLSBTYW1wVGltZSksCiAgICAgICAgIFdhaXRUaW1lX1NlYyA9IFdhaXRUaW1lX01pbiAqIDYwLAogICAgICAgICBXYWl0VGltZV9TZWMyID0gTkIgLSBTYW1wVGltZSwKICAgICAgICAgV2FpdFRpbWVfTWluMiA9IFdhaXRUaW1lX1NlYzIgLyA2MAogICAgICAgICkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQoKYXNzaWduKHBhc3RlMCgiVGVzdGluZ18iLCBpKSwKICAgICAgIFRlc3RpbmcKICAgICAgKQoKcm0oU2FtcCxUZXN0aW5nX0EsIFRlc3RpbmcpCnN0cihnZXQocGFzdGUwKCJUZXN0aW5nXyIsIGkpKSkKVmlldyhnZXQocGFzdGUwKCJUZXN0aW5nXyIsIGkpKSkKfQoKCiMgQmluZCBhbGwgdGhlIGluZGl2aWR1YWwgZGF0YWZyYW1lcyB0b2dldGhlci4KV2FpdERhdGFfRGF5UHVsbCA8LSBiaW5kX3Jvd3MoVGVzdGluZ18zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUZXN0aW5nXzQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRlc3RpbmdfNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGVzdGluZ182LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUZXN0aW5nXzcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBtdXRhdGUoV2FpdFRpbWVfU2VjMyA9IE5CIC0gU2FtcFRpbWUsCiAgICAgICAgIFdhaXRUaW1lX01pbjMgPSBXYWl0VGltZV9TZWMzIC8gNjAKICAgICAgICApICU+JSAKICBhcnJhbmdlKFJvdXRlLAogICAgICAgICAgU3RvcElEX0NsZWFuLAogICAgICAgICAgRXZlbnRfVGltZQogICAgICAgICApCgpybShUZXN0aW5nXzMsIFRlc3RpbmdfNCwgVGVzdGluZ181LCBUZXN0aW5nXzYsIFRlc3RpbmdfNykKc3RyKFdhaXREYXRhX0RheVB1bGwpClZpZXcoaGVhZChXYWl0RGF0YV9EYXlQdWxsLCA1MDApKQpWaWV3KHRhaWwoV2FpdERhdGFfRGF5UHVsbCwgNTAwKSkKCmBgYAoKCldhaXRpbmcgdGltZSBhbmFseXNlcy4KCk11bmdpbmcgYW5kIHNhbXBsaW5nIGRhdGEgdG8gZ28gZnJvbSB0aW1lIGJldGVlbiBidXNlcyB0byAiYXZlcmFnZSIgd2FpdGluZyB0aW1lLgoKQmFzaWMgaW52ZXN0aWdhdGlvbiBvZiBhbnkgbWlzc2luZyByb3dzIGZyb20gZGF0YSBwdWxsZWQgYnkgZGF5LgpgYGB7cn0KCkRpc3RpbmN0Um93TnVtX09HIDwtIGRpc3RpbmN0KHNlbGVjdChXYWl0RGF0YV9EYXlQdWxsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUm93TnVtX09HCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCgpzdHIoRGlzdGluY3RSb3dOdW1fT0cpCgpWaWV3KAphbnRpX2pvaW4oU2FtcCwKICAgICAgICAgIERpc3RpbmN0Um93TnVtX09HLAogICAgICAgICAgYnkgPSBjKCJSb3dOdW1fT0ciID0gIlJvd051bV9PRyIpCiAgICAgICAgICkKKQoKCiMgVGhlIHNhbXAgdGltZSBpcyBBRlRFUiB0aGUgbGFzdCBidXMgcGFzc2VkIHRoYXQgU3RvcElEX0NsZWFuClZpZXcoZmlsdGVyKFNhbXAsCiAgICAgICAgICAgIEV2ZW50X1RpbWUgPiAiMjAxNi0xMC0wNyAxOTo0ODo0MSIgJgogICAgICAgICAgICAgIFJvdXRlID09ICJYMiIgJgogICAgICAgICAgICAgIFN0b3BJRF9DbGVhbiA9PSAxMDAzNzc0CiAgICAgICAgICAgKQogICAgKQoKIyBOZXh0IEJ1cyAoTkIpIGNhbiBiZSBvbiB0aGUgbmV4dCBtb3JuaW5nClZpZXcoZmlsdGVyKFRlc3Rpbmc3LAogICAgICAgICAgICBTYW1wVGltZSA+ICIyMDE2LTEwLTA2IDIzOjU4OjAwIiAmCiAgICAgICAgICAgICAgU2FtcFRpbWUgPCAiMjAxNi0xMC0wNiAyMzo1OTo1OSIpCiAgICApCgpgYGAKCgpXYWl0aW5nIHRpbWUgYW5hbHlzZXMuCgpNdW5naW5nIGFuZCBzYW1wbGluZyBkYXRhIHRvIGdvIGZyb20gdGltZSBiZXRlZW4gYnVzZXMgdG8gImF2ZXJhZ2UiIHdhaXRpbmcgdGltZS4KCihQdWxscyBoZXJlIGFyZSBkb25lIGJ5IGdyb3VwaW5ncyBvZiBidXMgcm91dGVzLCBhcyB0aGUgZGF0YSBhcmUgdG9vIGxhcmdlIHRvIGRvIGF0IG9uY2UuKQoKRmlyc3QsIHdlIG5lZWQgdG8gZmluZCB0aGUgbW9zdCBjb21tb24gYnVzIHJvdXRlcy4KYGBge3J9CgpybShEaXN0aW5jdFJvd051bV9PRykKCgojIFZpZXcoaGVhZChOZXdUcmF2VGltZSwgNTAwKSkKCnNldC5zZWVkKDEyMzQ1Njc4OSkKQnVzR3JvdXBzIDwtIGdyb3VwX2J5KE5ld1RyYXZUaW1lLAogICAgICAgICAgICAgICAgICAgICAgUm91dGUKICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKENudF9OdW0gPSBuKCksCiAgICAgICAgICAgIENudF9QY3QgPSBDbnRfTnVtIC8gbnJvdyhOZXdUcmF2VGltZSkKICAgICAgICAgICApICU+JSAKICBhcnJhbmdlKGRlc2MoQ250X051bSkKICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFJvd051bSA9IHJvd19udW1iZXIoKSwKICAgICAgICAgUmFuZE51bSA9IHJ1bmlmKG4gPSAyNjgpLAogICAgICAgICBSb3V0ZUdyb3VwID0gaWZlbHNlKFJhbmROdW0gPD0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUmFuZE51bSA8PSAwLjQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShSYW5kTnVtIDw9IDAuNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAzLAogICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFJhbmROdW0gPD0gMC44LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkpKQogICAgICAgICkKCnN0cihCdXNHcm91cHMpClZpZXcoQnVzR3JvdXBzKQpzdW1tYXJ5KEJ1c0dyb3VwcykKCmBgYAoKCldhaXRpbmcgdGltZSBhbmFseXNlcy4KCk11bmdpbmcgYW5kIHNhbXBsaW5nIGRhdGEgdG8gZ28gZnJvbSB0aW1lIGJldGVlbiBidXNlcyB0byAiYXZlcmFnZSIgd2FpdGluZyB0aW1lLgoKKFB1bGxzIGhlcmUgYXJlIGRvbmUgYnkgZ3JvdXBpbmdzIG9mIGJ1cyByb3V0ZXMsIGFzIHRoZSBkYXRhIGFyZSB0b28gbGFyZ2UgdG8gZG8gYXQgb25jZS4pCmBgYHtyfQoKIyBWaWV3KGhlYWQoTmV3VHJhdlRpbWUsIDUwMCkpCgojIEZvciBlYWNoIHJlY29yZCwgY3JlYXRlIGEgcmFuZG9tIGRhdGV0aW1lIGJldHdlZW4gdGhlIGZpcnN0IGFuZCBsYXN0IHN0b3AgZm9yIHRoYXQgYnVzIHJvdXRlIChvbiB0aGF0IGRheSkuCmZvcihpIGluIDE6NSl7CiAgCnNldC5zZWVkKDEyMzQ1Njc4OSkKU2FtcCA8LSBsZWZ0X2pvaW4oTmV3VHJhdlRpbWUsCiAgICAgICAgICAgICAgICAgIEJ1c0dyb3VwcywKICAgICAgICAgICAgICAgICAgYnkgPSBjKCJSb3V0ZSIgPSAiUm91dGUiKQogICAgICAgICAgICAgICAgICApICU+JSAKICBzZWxlY3QoUm93TnVtX09HLAogICAgICAgICBSb3V0ZSwKICAgICAgICAgUm91dGVHcm91cCwKICAgICAgICAgRXZlbnRfVGltZV9EYXRlLAogICAgICAgICBTdG9wSURfQ2xlYW4sCiAgICAgICAgIHN0YXJ0c193aXRoKCJFdmVudCIpCiAgICAgICAgKSAlPiUgCiAgZmlsdGVyKFJvdXRlR3JvdXAgPT0gaSkgJT4lICAjIG5lZWRlZCB0byBkbyB0aGlzIGVhY2ggUm91dGVHcm91cCAoMS01KSBiZWNhdXNlIHRoZSBjb21wbGV0ZSBmaWxlIHdhcyB0b28gbGFyZ2UgdG8gZG8gYXQgb25jZQogIGxlZnRfam9pbihSb3V0ZU1pbk1heCwKICAgICAgICAgICAgYnkgPSBjKCJSb3V0ZSIgPSAiUm91dGUiLAogICAgICAgICAgICAgICAgICAgIkV2ZW50X1RpbWVfRGF0ZSIgPSAiRXZlbnRfVGltZV9EYXRlIgogICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKFNhbXBUaW1lID0gYXNfZGF0ZXRpbWUocnVuaWYobnJvdyguKSwgIzIwMDAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4gPSBNaW5UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heCA9IE1heFRpbWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHogPSAiQW1lcmljYS9OZXdfWW9yayIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICApICU+JSAKICBhcnJhbmdlKFJvdXRlLAogICAgICAgICAgU3RvcElEX0NsZWFuLAogICAgICAgICAgRXZlbnRfVGltZQogICAgICAgICApIAoKIyBzdHIoU2FtcCkKIyBWaWV3KGhlYWQoU2FtcCwgNTAwKSkKIyAKIyBWaWV3KAojIGdyb3VwX2J5KFNhbXAsCiMgICAgICAgICAgUm93TnVtX09HCiMgICAgICAgICApICU+JQojICAgc3VtbWFyaXNlKENudF9OdW0gPSBuKCksCiMgICAgICAgICAgICAgQ250X1BjdCA9IDEwMCAqIENudF9OdW0gLyBucm93KFNhbXApCiMgICAgICAgICAgICApICU+JQojICAgYXJyYW5nZShkZXNjKENudF9OdW0pKQojICkKCgojIEZvciBlYWNoIFJvdXRlIGFuZCBTdG9wSUQgY29tYmluYXRpb24sIGdldCBhbGwgdGhlIEV2ZW50X1RpbWUgdmFsdWVzIHRoYXQgYXJlIGFmdGVyIHRoZSBTYW1wVGltZSB2YWx1ZS4KIyBlc3RpbWF0aW5nIGFwcHJveCAyaHJzIG9mIHJ1bnRpbWUgZm9yIGFsbCAyLjhtIHJlY29yZHMKVGVzdGluZ19BIDwtIHNxbGRmKCIgICBTZWxlY3QgICAgICAgICAgICAgICB0MS4qCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLHQyLkV2ZW50X1RpbWUgICAgICAgICAgICAgYXMgTmV4dEJ1cwogICAgICAgICAgICAgICAgICAgICAgICBGcm9tICAgICAgICAgICAgICAgICBTYW1wICAgICAgICAgICAgICAgICAgICAgIGFzIHQxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW5uZXIgSm9pbiAgICAgIFNhbXAgICAgICAgICAgICAgICAgICAgICAgYXMgdDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBPbiAgICAgICAgICAgICAgdDEuUm91dGUgPSB0Mi5Sb3V0ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFuZCAgICAgICAgICAgICB0MS5TdG9wSURfQ2xlYW4gPSB0Mi5TdG9wSURfQ2xlYW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbmQgICAgICAgICAgICAgdDIuRXZlbnRfVGltZSA+IHQxLlNhbXBUaW1lCiAgICAgICAgICAgICAgICAgICAgICAgIE9yZGVyIEJ5ICAgICAgICAgICAgIHQxLlJvdXRlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLHQxLlN0b3BJRF9DbGVhbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICx0MS5FdmVudF9UaW1lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLHQyLkV2ZW50X1RpbWUKICAgICAgICAgICAgICAgICAgIgogICAgICAgICAgICAgICAgICkgJT4lIAogIG11dGF0ZShOQiA9IGFzX2RhdGV0aW1lKE5leHRCdXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHogPSAiQW1lcmljYS9OZXdfWW9yayIKICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICApCgojIHN0cihUZXN0aW5nX0EpCiMgVmlldyhoZWFkKFRlc3RpbmdfQSwgNTAwKSkKIyBWaWV3KGhlYWQoU2FtcCwgNTAwKSkKCgojIEZpbHRlciB0aGUgZGF0YWZyYW1lIHRvIG9ubHkgaW5jbHVkZSB0aGUgYnVzIGFycml2YWwgYXQgU3RvcElEIHRoYXQgaXMgdGhlIG5leHQgdG8gY29tZSBhZnRlciB0aGUgU2FtcFRpbWUuCiMgZXN0aW1hdGluZyBhcHByb3ggMjBtaW4gb2YgcnVudGltZSBmb3IgYWxsIDIuOG0gcmVjb3JkcwpUZXN0aW5nIDwtIHNlbGVjdChUZXN0aW5nX0EsCiAgICAgICAgICAgICAgICAgIC1OZXh0QnVzCiAgICAgICAgICAgICAgICAgKSAlPiUgCiAgZ3JvdXBfYnkoUm93TnVtX09HKSAlPiUgCiAgZmlsdGVyKE5CID09IG1pbihOQikKICAgICAgICApICU+JSAKICBhcnJhbmdlKFJvdXRlLAogICAgICAgICAgU3RvcElEX0NsZWFuLAogICAgICAgICAgRXZlbnRfVGltZQogICAgICAgICApICU+JSAKICBtdXRhdGUoV2FpdFRpbWVfTWluID0gYXMubnVtZXJpYyhOQiAtIFNhbXBUaW1lKSwKICAgICAgICAgV2FpdFRpbWVfU2VjID0gV2FpdFRpbWVfTWluICogNjAKICAgICAgICApICU+JSAKICBhcy5kYXRhLmZyYW1lKCkKCmFzc2lnbihwYXN0ZTAoIlRlc3RpbmciLCBpKSwKICAgICAgIFRlc3RpbmcKICAgICAgKQoKcm0oU2FtcCxUZXN0aW5nX0EsIFRlc3RpbmcpCnN0cihnZXQocGFzdGUwKCJUZXN0aW5nIiwgaSkpKQpWaWV3KGdldChwYXN0ZTAoIlRlc3RpbmciLCBpKSkpCn0KCgojIEJpbmQgYWxsIHRoZSBpbmRpdmlkdWFsIGRhdGFmcmFtZXMgdG9nZXRoZXIuCldhaXREYXRhX1JvdXRlUHVsbCA8LSBiaW5kX3Jvd3MoVGVzdGluZzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGVzdGluZzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGVzdGluZzMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGVzdGluZzQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGVzdGluZzUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBtdXRhdGUoV2FpdFRpbWVfU2VjMiA9IE5CIC0gU2FtcFRpbWUsCiAgICAgICAgIFdhaXRUaW1lX01pbjIgPSBXYWl0VGltZV9TZWMyIC8gNjAKICAgICAgICApICU+JSAKICBhcnJhbmdlKFJvdXRlLAogICAgICAgICAgU3RvcElEX0NsZWFuLAogICAgICAgICAgRXZlbnRfVGltZQogICAgICAgICApCgpybShCdXNHcm91cHMsIGksIFRlc3RpbmczLCBUZXN0aW5nNCwgVGVzdGluZzUsIFRlc3Rpbmc2LCBUZXN0aW5nNykKc3RyKFdhaXREYXRhX1JvdXRlUHVsbCkKVmlldyhoZWFkKFdhaXREYXRhX1JvdXRlUHVsbCwgNTAwKSkKVmlldyh0YWlsKFdhaXREYXRhX1JvdXRlUHVsbCwgNTAwKSkKCmBgYAoKCldhaXRpbmcgdGltZSBhbmFseXNlcy4KCk11bmdpbmcgYW5kIHNhbXBsaW5nIGRhdGEgdG8gZ28gZnJvbSB0aW1lIGJldGVlbiBidXNlcyB0byAiYXZlcmFnZSIgd2FpdGluZyB0aW1lLgoKQ29tcGFyZSBXYWl0RGF0YSBwdWxsZWQgYnkgZGF5IGFuZCBwdWxsZWQgYnkgcm91dGUuCmBgYHtyfQoKZGltKFdhaXREYXRhX1JvdXRlUHVsbCkKZGltKFdhaXREYXRhX0RheVB1bGwpCm5yb3coV2FpdERhdGFfUm91dGVQdWxsKSAtIG5yb3coV2FpdERhdGFfRGF5UHVsbCkKCldhaXREYXRhX0RpZmYgPC0gYW50aV9qb2luKFdhaXREYXRhX1JvdXRlUHVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgV2FpdERhdGFfRGF5UHVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJSb3dOdW1fT0ciID0gIlJvd051bV9PRyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHNlbGVjdCgtV2FpdFRpbWVfTWluLAogICAgICAgICAtV2FpdFRpbWVfU2VjCiAgICAgICAgKQoKc3RyKFdhaXREYXRhX0RpZmYpClZpZXcoaGVhZChXYWl0RGF0YV9EaWZmLCA1MDApKQoKVmlldyhmaWx0ZXIoV2FpdERhdGFfUm91dGVQdWxsLAogICAgICAgICAgICBSb3V0ZSA9PSAiWjgiICYKICAgICAgICAgICAgICBTdG9wSURfQ2xlYW4gPT0gMjAwNTQ2NQogICAgICAgICAgICAjIFJvd051bV9PRyA9IDI5MDI3NjAKICAgICAgICAgICAgIyBFdmVudF9UaW1lID0gMjAxNi0xMC0wNyAxOTo1MTo0NwogICAgICAgICAgICkKICAgICkKClZpZXcoZ3JvdXBfYnkoV2FpdERhdGFfRGlmZiwKICAgICAgICAgICAgICBSb3V0ZQogICAgICAgICAgICAgKSAlPiUgCiAgICAgICBzdW1tYXJpc2UoQ250X051bSA9IG4oKSwKICAgICAgICAgICAgICAgICBDbnRfUGN0ID0gQ250X051bSAvIG5yb3coV2FpdERhdGFfRGlmZikKICAgICAgICAgICAgICAgICkgJT4lIAogICAgICAgYXJyYW5nZShkZXNjKENudF9OdW0pCiAgICAgICAgICAgICAgKQogICAgKQoKVmlldyhmaWx0ZXIoV2FpdERhdGFfRGlmZiwKICAgICAgICAgICAgUm91dGUgPT0gIlMxIgogICAgICAgICAgICkKICAgICkKClZpZXcoZmlsdGVyKFdhaXREYXRhX1JvdXRlUHVsbCwKICAgICAgICAgICAgUm91dGUgPT0gIlMxIiAmCiAgICAgICAgICAgICAgU3RvcElEX0NsZWFuID09IDEwMDMxMzIKICAgICAgICAgICAgIyBSb3dOdW1fT0cgPSAxMTUxNzcwCiAgICAgICAgICAgICMgRXZlbnRfVGltZSA9IDIwMTYtMTAtMDcgMDk6MDc6MTIKICAgICAgICAgICApCiAgICApCgojIENhbid0IHRlbGwgd2h5IHRoZSBwdWxsIGJ5IGRheSBoYXMgbGVzcyByZWNvcmRzIHRoYW4gdGhlIHB1bGwgYnkgcm91dGUKCmBgYAoKCldhaXRpbmcgdGltZSBhbmFseXNlcy4KCk11bmdpbmcgYW5kIHNhbXBsaW5nIGRhdGEgdG8gZ28gZnJvbSB0aW1lIGJldGVlbiBidXNlcyB0byAiYXZlcmFnZSIgd2FpdGluZyB0aW1lLgoKQ29tcGFyZSBXYWl0RGF0YSAocHVsbGVkIGJ5IHJvdXRlKSBhbmQgb3JpZ2luYWwgZGF0YSAoTmV3VHJhdlRpbWUpLgpgYGB7cn0KCiMgcm0oV2FpdERhdGFfRGlmZikKCgpkaW0oTmV3VHJhdlRpbWUpICAjIDIsODA5LDUyOSByb3dzCmRpbShXYWl0RGF0YV9Sb3V0ZVB1bGwpICAjIDIsNzgwLDg0OCByb3dzCm5yb3coTmV3VHJhdlRpbWUpIC0gbnJvdyhXYWl0RGF0YV9Sb3V0ZVB1bGwpICAjIGlzIDI4LDY4MSByb3dzCgpzdHIoc2VsZWN0KE5ld1RyYXZUaW1lLAogICAgICAgICAgIC1tYXRjaGVzKCIocSgyfDV8KDk1KXwoOTgpKSl8TWVhbnxNZWR8Q250IikKICAgICAgICAgICkKICAgKQpzdHIoV2FpdERhdGFfUm91dGVQdWxsKQoKQ29tcGFyZV9OVFRfV0QgPC0gbGVmdF9qb2luKE5ld1RyYXZUaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KFdhaXREYXRhX1JvdXRlUHVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSb3dOdW1fT0csCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBSb3V0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSb3V0ZUdyb3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgU3RvcElEX0NsZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgRXZlbnRfVGltZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNaW5UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1heFRpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2FtcFRpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV2FpdFRpbWVfU2VjMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXYWl0VGltZV9NaW4yCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJSb3dOdW1fT0ciID0gIlJvd051bV9PRyIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHNlbGVjdCgtbWF0Y2hlcygiKHEoMnw1fCg5NSl8KDk4KSkpfE1lYW58TWVkfENudCIpCiAgICAgICAgKSAlPiUgCiAgYXJyYW5nZShSb3V0ZSwKICAgICAgICAgIFN0b3BJRF9DbGVhbiwKICAgICAgICAgIEV2ZW50X1RpbWUKICAgICAgICAgKQoKc3RyKENvbXBhcmVfTlRUX1dEKSAgIyAyLDgxMCwxMDkgcm93cyBvdmVyYWxsICAtLSAgMjksMjYxIHJvd3Mgd2l0aCBubyBtYXRjaApWaWV3KGhlYWQoQ29tcGFyZV9OVFRfV0QsIDUwMCkpClZpZXcoZmlsdGVyKENvbXBhcmVfTlRUX1dELAogICAgICAgICAgICBpcy5uYShNaW5UaW1lKQogICAgICAgICAgICkKICAgICkKCgoKVmlldyhhbnRpX2pvaW4oU2FtcCwKICAgICAgICAgICAgICAgZGlzdGluY3Qoc2VsZWN0KFdhaXREYXRhX1JvdXRlUHVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJvd051bV9PRwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgYnkgPSBjKCJSb3dOdW1fT0ciID0gIlJvd051bV9PRyIpCiAgICAgICAgICAgICAgKQogICAgKQoKIyBUaGUgU2FtcFRpbWUgaXMgQUZURVIgdGhlIGxhc3QgYnVzIHBhc3NlZCB0aGF0IFN0b3BJRF9DbGVhbgpWaWV3KGZpbHRlcihTYW1wLAogICAgICAgICAgICAgIFJvdXRlID09ICJYMiIgJgogICAgICAgICAgICAgIFN0b3BJRF9DbGVhbiA9PSAxMDAzNzc0CiAgICAgICAgICAgICMgUm93TnVtX09HID0gMTE0NjcyMwogICAgICAgICAgICAjIEV2ZW50X1RpbWUgPSAyMDE2LTEwLTA3IDE1OjMyOjE4CiAgICAgICAgICAgKQogICAgKQoKYGBgCgoKQ2xlYW4gdXAgdGhlIGRhdGEgYSBiaXQuCmBgYHtyfQoKcm0oQnVzR3JvdXBzLCBSb3V0ZU1pbk1heCwgU2FtcCwgVGVzdGluZzEsIFRlc3RpbmcyLCBUZXN0aW5nMywgVGVzdGluZzQsIFRlc3Rpbmc1LCBUZXN0aW5nXzMsIFRlc3RpbmdfNCwgVGVzdGluZ181LCBUZXN0aW5nXzYsIFRlc3RpbmdfNywgV2FpdERhdGFfRGF5UHVsbCwgV2FpdERhdGFfRGlmZikKCgpzdHIoQ29tcGFyZV9OVFRfV0QpClZpZXcoaGVhZChDb21wYXJlX05UVF9XRCwgNTAwKSkKVmlldyhoZWFkKG11dGF0ZShDb21wYXJlX05UVF9XRCwKICAgICAgICAgICAgICAgICBXVF9NaW4gPSBhcy5udW1lcmljKFdhaXRUaW1lX01pbjIpCiAgICAgICAgICAgICAgICApCiAgICAgICAgICkKICAgICkKCldhaXRUaW1lX0FzTnVtIDwtIENvbXBhcmVfTlRUX1dEICU+JSAKICBtdXRhdGUoUm91dGVTdG9wX0lEID0gZmFjdG9yKHBhc3RlKFJvdXRlLCBTdG9wSURfQ2xlYW4sIHNlcCA9ICJfXyIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICApCldhaXRUaW1lX0FzTnVtJFdhaXRUaW1lX1NlYzIgPC0gYXMubnVtZXJpYyhXYWl0VGltZV9Bc051bSRXYWl0VGltZV9TZWMyKQpXYWl0VGltZV9Bc051bSRXYWl0VGltZV9NaW4yIDwtIGFzLm51bWVyaWMoV2FpdFRpbWVfQXNOdW0kV2FpdFRpbWVfTWluMikKCnJtKENvbXBhcmVfTlRUX1dEKQpzdHIoV2FpdFRpbWVfQXNOdW0pCgpgYGAKCgpHZW5lcmFsIGV4cGxvcmF0aW9uIG9mIHdhaXQgdGltZXMuCmBgYHtyfQoKc3VtbWFyeShXYWl0VGltZV9Bc051bSRXYWl0VGltZV9NaW4yKQoKV1RfUXVhbnRpbGVzIDwtIGFzLmRhdGEuZnJhbWUocXVhbnRpbGUoV2FpdFRpbWVfQXNOdW0kV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYnMgPSBzZXEoMCwgMSwgMC4wMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCgpjb2xuYW1lcyhXVF9RdWFudGlsZXMpIDwtICJWYWx1ZV9NaW4iCgpXVF9RdWFudGlsZXMkVmFsdWVfU2VjID0gZm9ybWF0KHJvdW5kKFdUX1F1YW50aWxlcyRWYWx1ZV9NaW4gKiA2MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5zbWFsbCA9IDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKV1RfUXVhbnRpbGVzJFZhbHVlX0hyID0gZm9ybWF0KHJvdW5kKFdUX1F1YW50aWxlcyRWYWx1ZV9NaW4gLyA2MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc21hbGwgPSAyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCldUX1F1YW50aWxlcyRWYWx1ZV9NaW4gPSBmb3JtYXQocm91bmQoV1RfUXVhbnRpbGVzJFZhbHVlX01pbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5zbWFsbCA9IDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCldUX1F1YW50aWxlcyRRdWFudGlsZSA8LSBzZXEoMCwgMSwgMC4wMSkKCldUX1F1YW50aWxlcyA8LSBzZWxlY3QoV1RfUXVhbnRpbGVzLAogICAgICAgICAgICAgICAgICAgICAgIFF1YW50aWxlLAogICAgICAgICAgICAgICAgICAgICAgIFZhbHVlX1NlYywKICAgICAgICAgICAgICAgICAgICAgICBWYWx1ZV9NaW4sCiAgICAgICAgICAgICAgICAgICAgICAgVmFsdWVfSHIKICAgICAgICAgICAgICAgICAgICAgICkKCnN0cihXVF9RdWFudGlsZXMpClZpZXcoV1RfUXVhbnRpbGVzKQoKClZpZXcoYXJyYW5nZShXYWl0VGltZV9Bc051bSwKICAgICAgICAgICAgIGRlc2MoV2FpdFRpbWVfTWluMikKICAgICAgICAgICAgKSAlPiUgCiAgICAgICBoZWFkKC4sIDUwMDApCiAgICApCgpWaWV3KGZpbHRlcihXYWl0VGltZV9Bc051bSwKICAgICAgICAgICAgYmV0d2VlbihXYWl0VGltZV9NaW4yLCA2MCwgMjAwKQogICAgICAgICAgICkgJT4lIAogICAgICAgYXJyYW5nZShkZXNjKFdhaXRUaW1lX01pbjIpCiAgICAgICAgICAgICAgKSAKICAgICAjICU+JSAKICAgICAjICAgaGVhZCguLCA1MDAwKQogICAgKQoKIyBFeGFtcGxlIG9mIGV4dHJlbWUgd2FpdCB0aW1lcwpWaWV3KGZpbHRlcihXYWl0VGltZV9Bc051bSwKICAgICAgICAgICAgUm91dGUgPT0gIlcxMyIgJiAgIyBvbmx5IDIgYnVzIHBhc3NlcyBpbiB0aGUgZW50aXJlIGRhdGFzZXQKICAgICAgICAgICAgICBTdG9wSURfQ2xlYW4gPT0gMTAwMzcyOAogICAgICAgICAgICAjIEV2ZW50X1RpbWUgPSAyMDE2LTEwLTAzIDA4OjQyOjQ2CiAgICAgICAgICAgKQogICAgKQoKIyBFeGFtcGxlIG9mIGV4dHJlbWUgd2FpdCB0aW1lcwpWaWV3KGZpbHRlcihXYWl0VGltZV9Bc051bSwKICAgICAgICAgICAgUm91dGUgPT0gIlM0MSIgJiAgIyBvbmx5IDQgYnVzIHBhc3NlcyBpbiB0aGUgZW50aXJlIGRhdGFzZXQKICAgICAgICAgICAgICBTdG9wSURfQ2xlYW4gPT0gMTAwMTA5NQogICAgICAgICAgICAjIEV2ZW50X1RpbWUgPSAyMDE2LTEwLTA1IDE1OjQxOjQ3CiAgICAgICAgICAgKQogICAgKQoKIyBFeGFtcGxlIG9mIGV4dHJlbWUgd2FpdCB0aW1lcwpWaWV3KGZpbHRlcihXYWl0VGltZV9Bc051bSwKICAgICAgICAgICAgUm91dGUgPT0gIkQ4IiAmICAjIHJvdXRlIGhhcyBWRVJZIGxpbWl0ZWQgc2VydmljZSBhZnRlciBtaWRuaWdodAogICAgICAgICAgICAgIFN0b3BJRF9DbGVhbiA9PSAxMDAxNjY5CiAgICAgICAgICAgICMgRXZlbnRfVGltZSA9IDIwMTYtMTAtMDYgMjA6MzE6MTYKICAgICAgICAgICApCiAgICApCgpgYGAKCgpMb29rcyBsaWtlIHRoZXJlIG1pZ2h0IGJlIGFuIGlzc3VlIGluIHdhaXQgdGltZXMgd2hlbiB2ZXJ5IGZldyBSb3V0ZS1TdG9wIGNvbWJpbmF0aW9ucyBhcmUgaW5jbHVkZWQgaW4gdGhlIGRhdGFzZXQuICBMZXQncyBleHBsb3JlIHRoZXNlLgpgYGB7cn0KClJvdXRlU3RvcF9DbnRzIDwtIGdyb3VwX2J5KFdhaXRUaW1lX0FzTnVtLAogICAgICAgICAgICAgICAgICAgICAgICAgICBSb3V0ZVN0b3BfSUQKICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzdW1tYXJpc2UoUm91dGVTdG9wX0NudE51bSA9IG4oKSwKICAgICAgICAgICAgUm91dGVTdG9wX0NudFBjdCA9IFJvdXRlU3RvcF9DbnROdW0gLyBucm93KFdhaXRUaW1lX0FzTnVtKQogICAgICAgICAgICkgJT4lIAogIGFycmFuZ2UoUm91dGVTdG9wX0NudE51bSkKClZpZXcoUm91dGVTdG9wX0NudHMpCgoKUm91dGVTdG9wX0NudE9mQ250IDwtIGdyb3VwX2J5KFJvdXRlU3RvcF9DbnRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUm91dGVTdG9wX0NudE51bQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzdW1tYXJpc2UoUm91dGVTdG9wQ250X0NudE51bSA9IG4oKSwKICAgICAgICAgICAgUm91dGVTdG9wQ250X0NudFBjdCA9IFJvdXRlU3RvcENudF9DbnROdW0gLyBucm93KFJvdXRlU3RvcF9DbnRzKQogICAgICAgICAgICkgJT4lIAogIG11dGF0ZShSb3V0ZVN0b3BDbnRfQ250UGN0X0N1bVN1bSA9IGN1bXN1bShSb3V0ZVN0b3BDbnRfQ250UGN0KSwKICAgICAgICAgeCA9IDEgLSBSb3V0ZVN0b3BDbnRfQ250UGN0X0N1bVN1bQogICAgICAgICkgJT4lIAogIGFycmFuZ2UoUm91dGVTdG9wX0NudE51bSkKICAKIFZpZXcoUm91dGVTdG9wX0NudE9mQ250KQoKYGBgCgoKSGlzdG9ncmFtIG9mIHRoZSBjb3VudHMgb2YgUm91dGUtU3RvcElEIGNvbWJpbmF0aW9ucy4KYGBge3J9CgpSb3V0ZVN0b3BfQ250c19CYXIgPC0gZ2dwbG90KFJvdXRlU3RvcF9DbnRPZkNudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IFJvdXRlU3RvcF9DbnROdW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeSA9IC4uZGVuc2l0eS4uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBSb3V0ZVN0b3BDbnRfQ250TnVtCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgIyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUsIGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3VyID0gImdyZXk2MCIsIHNpemUgPSAwLjIpICsKICBnZW9tX2NvbChmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG91ciA9ICJncmV5NjAiLCBzaXplID0gMC4yKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDUwMCkKICAgICAgICAgICAgICAgICAgIyB5bGltID0gYygwLCAwLjAyKQogICAgICAgICAgICAgICAgICkgKwogIGxhYnModGl0bGUgPSAiVmFyaWF0aW9uIGluIFJvdXRlcyBQYXNzaW5nIGEgU3BlY2lmaWMgU3RvcCIsCiAgICAgICB4ID0gIk9jY3VycmVuY2VzIG9mIFJvdXRlLVN0b3BJRCBDb21iaWFudGlvbnMiLAogICAgICAgeSA9ICJDb3VudHMiCiAgICAgICkKClJvdXRlU3RvcF9DbnRzX0JhcgoKYGBgCgoKQ3JlYXRlIGEgbmV3IGRhdGFzZXQgbGltaXRpbmcgZXh0cmVtZWx5IHNtYWxsIGNvdW50cyBvZiBSb3V0ZS1TdG9wSUQgY29tYmluYXRpb25zLgpgYGB7cn0KCldhaXRUaW1lX1J0ZUNudHMgPC0gbGVmdF9qb2luKFdhaXRUaW1lX0FzTnVtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSb3V0ZVN0b3BfQ250cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJSb3V0ZVN0b3BfSUQiID0gIlJvdXRlU3RvcF9JRCIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc2VsZWN0KC1Sb3V0ZVN0b3BfQ250UGN0KQoKZGltKFdhaXRUaW1lX0FzTnVtKQpkaW0oV2FpdFRpbWVfUnRlQ250cykKCnJtKFdhaXRUaW1lX0FzTnVtKQpzdHIoV2FpdFRpbWVfUnRlQ250cykKCgojIFRvdGFsIHJvd3MKbnJvdyhXYWl0VGltZV9SdGVDbnRzKQoKIyBSb3dzIG9mIHJhcmUgUm91dGVTdG9wcwpucm93KGZpbHRlcihXYWl0VGltZV9SdGVDbnRzLAogICAgICAgICAgICBSb3V0ZVN0b3BfQ250TnVtIDw9IDYwCiAgICAgICAgICAgKQogICAgKSAvIG5yb3coV2FpdFRpbWVfUnRlQ250cykKCiMgUm93cyBvZiBleHRyZW1lbHkgbG9uZyB3YWl0IHRpbWVzCm5yb3coZmlsdGVyKFdhaXRUaW1lX1J0ZUNudHMsCiAgICAgICAgICAgIFdhaXRUaW1lX01pbjIgPiAxODAKICAgICAgICAgICApCiAgICApIC8gbnJvdyhXYWl0VGltZV9SdGVDbnRzKQoKCnNlbGVjdChXYWl0VGltZV9SdGVDbnRzLAogICAgICAgV2FpdFRpbWVfTWluMgogICAgICApICU+JSAKICBzdW1tYXJ5KCkKCmZpbHRlcihXYWl0VGltZV9SdGVDbnRzLAogICAgICAgUm91dGVTdG9wX0NudE51bSA+IDYwICAjIDEyIHBhc3NlcyBwZXIgZGF5IGluIGEgNS1kYXkgZGF0YXNldAogICAgICApICU+JSAKICBzZWxlY3QoV2FpdFRpbWVfTWluMikgJT4lIAogIHN1bW1hcnkoKQoKZmlsdGVyKFdhaXRUaW1lX1J0ZUNudHMsCiAgICAgICBXYWl0VGltZV9NaW4yIDwgMTgwICAjIHByb2JhYmx5IG1lYW5zIHRoYXQgc29tZXRoaW5nIHdlbnQgd3JvbmcKICAgICAgKSAlPiUgCiAgc2VsZWN0KFdhaXRUaW1lX01pbjIpICU+JSAKICBzdW1tYXJ5KCkKCgoKYSA8LSBhcy5kYXRhLmZyYW1lKHNlbGVjdChXYWl0VGltZV9SdGVDbnRzLAogICAgICAgICAgICAgICAgICAgICAgICAgIFdhaXRUaW1lX01pbjIKICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogICAgICAgICAgICAgICAgICAgICBxdWFudGlsZShwcm9icyA9IHNlcSgwLCAxLCAwLjAxKSwgbmEucm0gPSBUUlVFKQogICAgICAgICAgICAgICAgICApCgpiIDwtIGFzLmRhdGEuZnJhbWUoZmlsdGVyKFdhaXRUaW1lX1J0ZUNudHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgUm91dGVTdG9wX0NudE51bSA+IDYwCiAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KFdhaXRUaW1lX01pbjIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgcXVhbnRpbGUocHJvYnMgPSBzZXEoMCwgMSwgMC4wMSksIG5hLnJtID0gVFJVRSkKICAgICAgICAgICAgICAgICAgKQoKYyA8LSBhcy5kYXRhLmZyYW1lKGZpbHRlcihXYWl0VGltZV9SdGVDbnRzLAogICAgICAgICAgICAgICAgICAgICAgICAgIFdhaXRUaW1lX01pbjIgPCAxODAKICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogICAgICAgICAgICAgICAgICAgICBzZWxlY3QoV2FpdFRpbWVfTWluMikgJT4lIAogICAgICAgICAgICAgICAgICAgICBxdWFudGlsZShwcm9icyA9IHNlcSgwLCAxLCAwLjAxKSwgbmEucm0gPSBUUlVFKQogICAgICAgICAgICAgICAgICApCgpXVF9GaWx0ZXJfUXVhbnRpbGVzIDwtIGJpbmRfY29scyhhLCBiLCBjKSAlPiUgCiAgbXV0YXRlKFF1YW50aWxlID0gc2VxKDAsIDEsIDAuMDEpCiAgICAgICAgKQoKY29sbmFtZXMoV1RfRmlsdGVyX1F1YW50aWxlcykgPC0gYygiQWxsIiwgIlJ0ZVN0cEFidjYwIiwgIldUQmx3MTgwIiwgIlF1YW50aWxlIikKcm0oYSwgYiwgYykKVmlldyhXVF9GaWx0ZXJfUXVhbnRpbGVzKQoKYGBgCgoKSGlzdG9ncmFtIG9mIGFsbCB3YWl0IHRpbWVzLgpgYGB7cn0KCldhaXRUaW1lX0FsbEJ1c19IaXN0RGVuIDwtIGdncGxvdChmaWx0ZXIoc2VsZWN0KFdhaXRUaW1lX1J0ZUNudHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdhaXRUaW1lX01pbjIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShXYWl0VGltZV9NaW4yKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gLi5kZW5zaXR5Li4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUsIGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3VyID0gImdyZXk2MCIsIHNpemUgPSAwLjIpICsKICBnZW9tX2xpbmUoc3RhdCA9ICJkZW5zaXR5IiwgY29sb3VyID0gInJlZCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDMwMCwgMzApCiAgICAgICAgICAgICAgICAgICAgKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDMwMCksCiAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDAsIDAuMDM1KQogICAgICAgICAgICAgICAgICkgKwogIGxhYnModGl0bGUgPSAiVmFyaWF0aW9uIGluIFdhaXQgVGltZSIsCiAgICAgICB4ID0gIldhaXQgVGltZSAobWluKSIsCiAgICAgICB5ID0gIkRlbnNpdHkiCiAgICAgICkKCldhaXRUaW1lX0FsbEJ1c19IaXN0RGVuCgpgYGAKCgpCb3ggcGxvdHMgZm9yIFdhaXRUaW1lIChhbGwgYnVzc2VzLCBieSBaaXAgQ29kZSkuCmBgYHtyfQoKIyBDb3VudF9WYWx1ZXMgaXMgbmVlZGVkIHRvIGRpc3BsYXkgdGhlIG1lZGlhbnMgb24gdGhlIGJveCBwbG90cwpCdXNSb3V0ZSA8LSBzZWxlY3QoV2FpdFRpbWVfUnRlQ250cywKICAgICAgICAgICAgICAgICAgIFJvdXRlLAogICAgICAgICAgICAgICAgICAgV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICAgICAgIFN0b3BfWmlwCiAgICAgICAgICAgICAgICAgICkgJT4lIAogIGZpbHRlcihSb3V0ZSA9PSAiWDIiKQoKQ291bnRWYWx1ZXNfQWxsQnVzX1ppcCA8LSBkZHBseShCdXNSb3V0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuKFN0b3BfWmlwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVmFsdWVfQ291bnRzID0gbWVkaWFuKFdhaXRUaW1lX01pbjIsIG5hLnJtID0gVFJVRSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCldhaXRUaW1lX0FsbEJ1c19aaXBfQm94IDwtIGdncGxvdChCdXNSb3V0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhmYWN0b3IoU3RvcF9aaXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdhaXRUaW1lX01pbjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGZhY3RvcihTdG9wX1ppcCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArIAogIGdlb21fYm94cGxvdChvdXRsaWVyLmNvbG91cj0icmVkIiwgbm90Y2g9VFJVRSwgbmEucm0gPSBUUlVFKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBDb3VudFZhbHVlc19BbGxCdXNfWmlwLAogICAgICAgICAgICBhZXMoeSA9IFZhbHVlX0NvdW50cywKICAgICAgICAgICAgICAgIGxhYmVsID0gZm9ybWF0KHJvdW5kKFZhbHVlX0NvdW50cywgZGlnaXRzID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc21hbGwgPSAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNQogICAgICAgICAgICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1KSkgKwogIGNvb3JkX2NhcnRlc2lhbigjIHhsaW0gPSBjKDAsIDE4MCksCiAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDAsIDQ1KQogICAgICAgICAgICAgICAgICkgKwogIGxhYnModGl0bGUgPSAiV2FpdGluZyBUaW1lIGF0IGEgR2l2ZW4gU3RvcCAoZm9yIHRoZSBYMikiLAogICAgICAgeCA9ICJaaXAgQ29kZSBvZiBEZXN0aW5hdGlvbiIsCiAgICAgICB5ID0gIldhaXRpbmcgVGltZSAobWluKSIKICAgICAgKQoKV2FpdFRpbWVfQWxsQnVzX1ppcF9Cb3gKCmBgYAoKClRlc3QgaW52ZXN0aWdhdGlvbiBvZiBqdXN0IHRoZSBYMiBSb3V0ZS4gVmlvbGluIHBsb3RzIGZvciB0aW1lIGJldHdlZW4gYnVzIGFycml2YWxzIChieSBaaXAgQ29kZSkuCmBgYHtyfQoKV2FpdFRpbWVfQWxsQnVzX1ppcF9WaW9saW4gPC0gZ2dwbG90KEJ1c1JvdXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGZhY3RvcihTdG9wX1ppcCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZmFjdG9yKFN0b3BfWmlwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsgCiAgZ2VvbV92aW9saW4oZHJhd19xdWFudGlsZXMgPSBjKDAuMjUsIDAuNSwgMC43NSksCiAgICAgICAgICAgICAgdHJpbSA9IFRSVUUsCiAgICAgICAgICAgICAgc2NhbGUgPSAiY291bnQiLAogICAgICAgICAgICAgIG5hLnJtID0gVFJVRSwKICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IE5BLAogICAgICAgICAgICAgIGluaGVyaXQuYWVzID0gVFJVRQogICAgICAgICAgICAgKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBDb3VudFZhbHVlc19BbGxCdXNfWmlwLAogICAgICAgICAgICBhZXMoeSA9IFZhbHVlX0NvdW50cywKICAgICAgICAgICAgICAgIGxhYmVsID0gZm9ybWF0KHJvdW5kKFZhbHVlX0NvdW50cywgZGlnaXRzID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc21hbGwgPSAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgc2l6ZSA9IDMuNSwKICAgICAgICAgICAgdmp1c3QgPSAtMC41CiAgICAgICAgICAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUpKSArCiAgY29vcmRfY2FydGVzaWFuKCMgeGxpbSA9IGMoMCwgMTgwKSwKICAgICAgICAgICAgICAgICAgeWxpbSA9IGMoMCwgNDUpCiAgICAgICAgICAgICAgICAgKSArCiAgbGFicyh0aXRsZSA9ICJXYWl0aW5nIFRpbWUgYXQgYSBHaXZlbiBTdG9wIChmb3IgdGhlIFgyKSIsCiAgICAgICB4ID0gIlppcCBDb2RlIG9mIERlc3RpbmF0aW9uIiwKICAgICAgIHkgPSAiV2FpdGluZyBUaW1lIChtaW4pIgogICAgICApCgpUaW1lQnR3RXZlbnRzX1gyX1Zpb2xpblBsb3RfegoKYGBgCgoKQm94IHBsb3RzIGZvciBXYWl0VGltZSAoWmlwIENvZGUsIGJ5IEhvdXJHcm91cFppcCkuCmBgYHtyfQoKIyBDb3VudF9WYWx1ZXMgaXMgbmVlZGVkIHRvIGRpc3BsYXkgdGhlIG1lZGlhbnMgb24gdGhlIGJveCBwbG90cwpaaXAgPC0gc2VsZWN0KFdhaXRUaW1lX1J0ZUNudHMsCiAgICAgICAgICAgICAgUm91dGUsCiAgICAgICAgICAgICAgV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICBTdG9wX1ppcCwKICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyR3JvdXAKICAgICAgICAgICAgICkgJT4lIAogIGZpbHRlcihTdG9wX1ppcCA9PSAyMDAwMikKCkNvdW50VmFsdWVzX0FsbEJ1c19IRyA8LSBkZHBseShaaXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuKEV2ZW50X1RpbWVfSHJHcm91cCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWYWx1ZV9Db3VudHMgPSBtZWRpYW4oV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCldhaXRUaW1lX0FsbEJ1c19IR19Cb3ggPC0gZ2dwbG90KFppcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGZhY3RvcihFdmVudF9UaW1lX0hyR3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBmYWN0b3IoRXZlbnRfVGltZV9Ickdyb3VwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArIAogIGdlb21fYm94cGxvdChvdXRsaWVyLmNvbG91cj0icmVkIiwgbm90Y2g9VFJVRSwgbmEucm0gPSBUUlVFKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBDb3VudFZhbHVlc19BbGxCdXNfSEcsCiAgICAgICAgICAgIGFlcyh5ID0gVmFsdWVfQ291bnRzLAogICAgICAgICAgICAgICAgbGFiZWwgPSBmb3JtYXQocm91bmQoVmFsdWVfQ291bnRzLCBkaWdpdHMgPSAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5zbWFsbCA9IDEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICApLAogICAgICAgICAgICBzaXplID0gMi41LAogICAgICAgICAgICB2anVzdCA9IC0wLjUKICAgICAgICAgICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSkpICsKICBjb29yZF9jYXJ0ZXNpYW4oIyB4bGltID0gYygwLCAxODApLAogICAgICAgICAgICAgICAgICB5bGltID0gYygwLCA0NSkKICAgICAgICAgICAgICAgICApICsKICBsYWJzKHRpdGxlID0gIldhaXRpbmcgVGltZSBhdCBhIEdpdmVuIFN0b3AgKGZvciBaaXAgMjAwMDIpIiwKICAgICAgIHggPSAiSG91ciBHcm91cCIsCiAgICAgICB5ID0gIldhaXRpbmcgVGltZSAobWluKSIKICAgICAgKQogICMgZmFjZXRfd3JhcCh+U3RvcF9aaXAKICAjICAgICAgICAgICAgIyBucm93ID0gNQogICMgICAgICAgICAgICkKCldhaXRUaW1lX0FsbEJ1c19IR19Cb3gKCmBgYAoKClZpb2xpbiBwbG90cyBmb3IgV2FpdFRpbWUgKFppcCBDb2RlLCBieSBIb3VyR3JvdXBaaXApLgpgYGB7cn0KCldhaXRUaW1lX0FsbEJ1c19IR19WbG4gPC0gZ2dwbG90KFppcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGZhY3RvcihFdmVudF9UaW1lX0hyR3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBmYWN0b3IoRXZlbnRfVGltZV9Ickdyb3VwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArIAogIGdlb21fdmlvbGluKGRyYXdfcXVhbnRpbGVzID0gYygwLjI1LCAwLjUsIDAuNzUpLAogICAgICAgICAgICAgIHRyaW0gPSBUUlVFLAogICAgICAgICAgICAgIHNjYWxlID0gImNvdW50IiwKICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUsCiAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBOQSwKICAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IFRSVUUKICAgICAgICAgICAgICkgKwogIGdlb21fdGV4dChkYXRhID0gQ291bnRWYWx1ZXNfQWxsQnVzX0hHLAogICAgICAgICAgICBhZXMoeSA9IFZhbHVlX0NvdW50cywKICAgICAgICAgICAgICAgIGxhYmVsID0gZm9ybWF0KHJvdW5kKFZhbHVlX0NvdW50cywgZGlnaXRzID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc21hbGwgPSAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgc2l6ZSA9IDIuNSwKICAgICAgICAgICAgdmp1c3QgPSAtMC41CiAgICAgICAgICAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUpKSArCiAgY29vcmRfY2FydGVzaWFuKCMgeGxpbSA9IGMoMCwgMTgwKSwKICAgICAgICAgICAgICAgICAgeWxpbSA9IGMoMCwgOTApCiAgICAgICAgICAgICAgICAgKSArCiAgbGFicyh0aXRsZSA9ICJXYWl0aW5nIFRpbWUgYXQgYSBHaXZlbiBTdG9wIChmb3IgWmlwIDIwMDAyKSIsCiAgICAgICB4ID0gIkhvdXIgR3JvdXAiLAogICAgICAgeSA9ICJXYWl0aW5nIFRpbWUgKG1pbikiCiAgICAgICkKICAjIGZhY2V0X3dyYXAoflN0b3BfWmlwCiAgIyAgICAgICAgICAgICMgbnJvdyA9IDUKICAjICAgICAgICAgICApCgpXYWl0VGltZV9BbGxCdXNfSEdfVmxuCgpgYGAKCgpCb3ggcGxvdHMgZm9yIFdhaXRUaW1lIChSb3V0ZSwgYnkgSG91ckdyb3VwWmlwKS4KYGBge3J9CgojIENvdW50X1ZhbHVlcyBpcyBuZWVkZWQgdG8gZGlzcGxheSB0aGUgbWVkaWFucyBvbiB0aGUgYm94IHBsb3RzClJ0ZSA8LSBzZWxlY3QoV2FpdFRpbWVfUnRlQ250cywKICAgICAgICAgICAgICBSb3V0ZSwKICAgICAgICAgICAgICBXYWl0VGltZV9NaW4yLAogICAgICAgICAgICAgIFN0b3BfWmlwLAogICAgICAgICAgICAgIEV2ZW50X1RpbWVfSHJHcm91cAogICAgICAgICAgICAgKSAlPiUgCiAgZmlsdGVyKFJvdXRlID09ICJYMiIpCgpDb3VudFZhbHVlc19BbGxCdXNfUnRlSEcgPC0gZ3JvdXBfYnkoUnRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9Ickdyb3VwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHN1bW1hcmlzZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWYWx1ZV9Db3VudHMgPSBtZWRpYW4oV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZDID0gcXVhbnRpbGUoV2FpdFRpbWVfTWluMiwgcHJvYnMgPSAwLjksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogIAogICMgZGRwbHkoUnRlLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4oRXZlbnRfVGltZV9Ickdyb3VwKSwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVmFsdWVfQ291bnRzID0gbWVkaWFuKFdhaXRUaW1lX01pbjIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCldhaXRUaW1lX0FsbEJ1c19SdGVIR19Cb3ggPC0gZ2dwbG90KFJ0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGZhY3RvcihFdmVudF9UaW1lX0hyR3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBmYWN0b3IoRXZlbnRfVGltZV9Ickdyb3VwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArIAogIGdlb21fYm94cGxvdChvdXRsaWVyLmNvbG91cj0icmVkIiwgbm90Y2g9VFJVRSwgbmEucm0gPSBUUlVFKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBDb3VudFZhbHVlc19BbGxCdXNfUnRlSEcsCiAgICAgICAgICAgIGFlcyh5ID0gVmFsdWVfQ291bnRzLAogICAgICAgICAgICAgICAgbGFiZWwgPSBmb3JtYXQocm91bmQoVmFsdWVfQ291bnRzLCBkaWdpdHMgPSAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5zbWFsbCA9IDEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICApLAogICAgICAgICAgICBzaXplID0gMi41LAogICAgICAgICAgICB2anVzdCA9IC0wLjUKICAgICAgICAgICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSkpICsKICBjb29yZF9jYXJ0ZXNpYW4oIyB4bGltID0gYygwLCAxODApLAogICAgICAgICAgICAgICAgICB5bGltID0gYygwLCBtYXgoQ291bnRWYWx1ZXNfQWxsQnVzX1J0ZUhHJFZDKSkKICAgICAgICAgICAgICAgICApICsKICBsYWJzKHRpdGxlID0gIldhaXRpbmcgVGltZSBhdCBhIEdpdmVuIFN0b3AiLAogICAgICAgc3VidGl0bGUgPSAoIlJvdXRlIFgyIiksCiAgICAgICB4ID0gIkhvdXIgR3JvdXAiLAogICAgICAgeSA9ICJXYWl0aW5nIFRpbWUgKG1pbikiCiAgICAgICkgCiMgKwojICAgZmFjZXRfd3JhcCh+U3RvcF9aaXAKIyAgICAgICAgICAgICAgIyBucm93ID0gNQojICAgICAgICAgICAgICkKCldhaXRUaW1lX0FsbEJ1c19SdGVIR19Cb3gKCmBgYAoKClZpb2xpbiBwbG90cyBmb3IgV2FpdFRpbWUgKFppcCBDb2RlLCBieSBIb3VyR3JvdXBaaXApLgpgYGB7cn0KCldhaXRUaW1lX0FsbEJ1c19SdGVIR19WbG4gPC0gZ2dwbG90KFJ0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGZhY3RvcihFdmVudF9UaW1lX0hyR3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV2FpdFRpbWVfTWluMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBmYWN0b3IoRXZlbnRfVGltZV9Ickdyb3VwKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArIAogIGdlb21fdmlvbGluKGRyYXdfcXVhbnRpbGVzID0gYygwLjI1LCAwLjUsIDAuNzUpLAogICAgICAgICAgICAgIHRyaW0gPSBUUlVFLAogICAgICAgICAgICAgIHNjYWxlID0gImNvdW50IiwKICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUsCiAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBOQSwKICAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IFRSVUUKICAgICAgICAgICAgICkgKwogIGdlb21fdGV4dChkYXRhID0gQ291bnRWYWx1ZXNfQWxsQnVzX1J0ZUhHLAogICAgICAgICAgICBhZXMoeSA9IFZhbHVlX0NvdW50cywKICAgICAgICAgICAgICAgIGxhYmVsID0gZm9ybWF0KHJvdW5kKFZhbHVlX0NvdW50cywgZGlnaXRzID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc21hbGwgPSAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgc2l6ZSA9IDIuNSwKICAgICAgICAgICAgdmp1c3QgPSAtMC41CiAgICAgICAgICAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUpKSArCiAgY29vcmRfY2FydGVzaWFuKCMgeGxpbSA9IGMoMCwgMTgwKSwKICAgICAgICAgICAgICAgICAgeWxpbSA9IGMoMCwgNDUpCiAgICAgICAgICAgICAgICAgKSArCiAgbGFicyh0aXRsZSA9ICJXYWl0aW5nIFRpbWUgYXQgYSBHaXZlbiBTdG9wIiwKICAgICAgIHN1YnRpdGxlID0gKCIoUm91dGUgWDIpIiksCiAgICAgICB4ID0gIkhvdXIgR3JvdXAiLAogICAgICAgeSA9ICJXYWl0aW5nIFRpbWUgKG1pbikiCiAgICAgICkgKwogIGZhY2V0X3dyYXAoflN0b3BfWmlwCiAgICAgICAgICAgICAjIG5yb3cgPSA1CiAgICAgICAgICAgICkKCldhaXRUaW1lX0FsbEJ1c19SdGVIR19WbG4KCmBgYAoKClgyIFBlcmNlbnRpbGVzIExpbmUgR3JhcGggVGVzdC4KYGBge3J9CgpYMl9QY3QgPC0gc2VsZWN0KFdhaXRUaW1lX1J0ZUNudHMsCiAgICAgICAgICAgICAgICAgUm91dGUsCiAgICAgICAgICAgICAgICAgU3RvcF9aaXAsCiAgICAgICAgICAgICAgICAgRXZlbnRfVGltZV9EYXRlLAogICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfRGF5LAogICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfSHJHcm91cCwKICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyLAogICAgICAgICAgICAgICAgIExhdGl0dWRlLAogICAgICAgICAgICAgICAgIExvbmdpdHVkZSwKICAgICAgICAgICAgICAgICBXYWl0VGltZV9NaW4yCiAgICAgICAgICAgICAgICApICU+JSAKICBmaWx0ZXIoUm91dGUgPT0gIlgyIikgJT4lIAogIGdyb3VwX2J5KEV2ZW50X1RpbWVfSHIsCiAgICAgICAgICAgU3RvcF9aaXAKICAgICAgICAgICkgJT4lIAogIHN1bW1hcmlzZShQY3Q1MCA9IHF1YW50aWxlKFdhaXRUaW1lX01pbjIsIHByb2JzID0gMC41LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBQY3Q2MCA9IHF1YW50aWxlKFdhaXRUaW1lX01pbjIsIHByb2JzID0gMC42LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBQY3Q3MCA9IHF1YW50aWxlKFdhaXRUaW1lX01pbjIsIHByb2JzID0gMC43LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBQY3Q4MCA9IHF1YW50aWxlKFdhaXRUaW1lX01pbjIsIHByb2JzID0gMC44LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBQY3Q5MCA9IHF1YW50aWxlKFdhaXRUaW1lX01pbjIsIHByb2JzID0gMC45LCBuYS5ybSA9IFRSVUUpCiAgICAgICAgICAgKQoKc3RyKFgyX1BjdCkKVmlldyhYMl9QY3QpCgoKWDJfTG9uZyA8LSBnYXRoZXIoWDJfUGN0LAogICAgICAgICAgICAgICAgICBrZXkgPSBQZXJjZW50aWxlLAogICAgICAgICAgICAgICAgICB2YWx1ZSA9IFBjdGlsZSwKICAgICAgICAgICAgICAgICAgUGN0NTAsCiAgICAgICAgICAgICAgICAgIFBjdDYwLAogICAgICAgICAgICAgICAgICBQY3Q3MCwKICAgICAgICAgICAgICAgICAgUGN0ODAsCiAgICAgICAgICAgICAgICAgIFBjdDkwCiAgICAgICAgICAgICAgICApCgpzdHIoWDJfTG9uZykKVmlldyhYMl9Mb25nKQoKClgyX1dhaXRCeUhyX0xpbmUgPC0gZ2dwbG90KFgyX0xvbmcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gRXZlbnRfVGltZV9IciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBQY3RpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3IoUGVyY2VudGlsZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogIGdlb21fbGluZSgpICsKICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgICAgICApICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgMjMpCiAgICAgICAgICAgICAgICAgICMgeWxpbSA9IGMoMCwgNDUpCiAgICAgICAgICAgICAgICAgKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMjMsIDIpCiAgICAgICAgICAgICAgICAgICAgKSArCiAgbGFicyh0aXRsZSA9ICJXYWl0aW5nIFRpbWUgVGhyb3VnaG91dCB0aGUgRGF5IiwKICAgICAgIHN1YnRpdGxlID0gKCIoUm91dGUgWDIpIiksCiAgICAgICB4ID0gIkhvdXIgb2YgdGhlIERheSIsCiAgICAgICB5ID0gIldhaXRpbmcgVGltZSAobWluKSIKICAgICAgKSArCiAgZmFjZXRfd3JhcCh+U3RvcF9aaXApCgpYMl9XYWl0QnlIcl9MaW5lCgpgYGAKCgoKCgpHRVQgREFUQSBSRUFEWSBGT1IgU0hJTlkKYGBge3J9CgojIHN0cihXYWl0VGltZV9SdGVDbnRzKQoKU2hpbnlfV2FpdERhdGFfQmFzZSA8LSBzZWxlY3QoV2FpdFRpbWVfUnRlQ250cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUm91dGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0b3BfWmlwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0RhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfRGF5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyR3JvdXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEV2ZW50X1RpbWVfSHIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExhdGl0dWRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb25naXR1ZGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdhaXRUaW1lX01pbjIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCgpTaGlueV9XYWl0RGF0YV9CYXNlJFJvdXRlIDwtIGZhY3RvcihTaGlueV9XYWl0RGF0YV9CYXNlJFJvdXRlKQoKc3RyKFNoaW55X1dhaXREYXRhX0Jhc2UpCgp3cml0ZS50YWJsZShTaGlueV9XYWl0RGF0YV9CYXNlLAogICAgICAgICAgICAiU2hpbnlfV2FpdERhdGFfQmFzZS50eHQiLAogICAgICAgICAgICBxdW90ZSA9IEZBTFNFLAogICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRQogICAgICAgICAgICkKIyBybShTaGlueV9XYWl0RGF0YV9CYXNlKQoKYGBgCgoKClRlc3RpbmcgbWFwcGluZyBmdW5jdGlvbmFsdGl5CmBgYHtyfQoKIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImRrYWhsZS9nZ21hcCIpCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJoYWRsZXkvZ2dwbG90MiIpCiMgaW5zdGFsbC5wYWNrYWdlcygiZ2dtYXAiLCB0eXBlID0gInNvdXJjZSIpCgojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YignaGFkbGV5L2dncGxvdDInKQpkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImhhZGxleS9nZ3Bsb3QyQHYyLjIuMCIpCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCd0aG9tYXNwODUvZ2dmb3JjZScpCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCd0aG9tYXNwODUvZ2dyYXBoJykKIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoJ3Nsb3drb3cvZ2dyZXBlbCcpCgoKCgoKCgp0cmFjdCA8LSAKICByZWFkT0dSKGRzbiA9ICIvVXNlcnMvbWR0dXJzZS9EZXNrdG9wL0FuYWx5dGljcy9EQ01ldHJvQnVzL2NiXzIwMTVfMTFfdHJhY3RfNTAwayIsCiAgICAgICAgICBsYXllciA9ICJjYl8yMDE1XzExX3RyYWN0XzUwMGsiCiAgICAgICAgICkKICAKY2xhc3ModHJhY3QpCgoKIyBjb252ZXJ0IHRoZSBHRU9JRCB0byBhIGNoYXJhY3Rlcgp0cmFjdEBkYXRhJEdFT0lEIDwtIGFzLmNoYXJhY3Rlcih0cmFjdEBkYXRhJEdFT0lEKQoKc3RyKHRyYWN0QGRhdGEpCgoKCmdndHJhY3QgPC0gdGlkeSh0cmFjdCkjLCByZWdpb24gPSAiR0VPSUQiKQpzdHIoZ2d0cmFjdCkKc3VtbWFyeShnZ3RyYWN0KQoKCgptYXAgPC0gZ2V0X21hcChsb2NhdGlvbiA9IGMobG9uID0gLTc3LjAzNjc2LCBsYXQgPSAzOC44OTc4NCksCiAgICAgICAgICAgICAgIHNvdXJjZSA9ICJnb29nbGUiLAogICAgICAgICAgICAgICAjIG1hcHR5cGUgPSAicm9hZG1hcCIKICAgICAgICAgICAgICAgem9vbSA9IDEyCiAgICAgICAgICAgICAgKQoKZ2dtYXAobWFwKSArCiAgZ2VvbV9wb2x5Z29uKGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCksIAogICAgICAgICAgICAgICBkYXRhID0gZ2d0cmFjdCwKICAgICAgICAgICAgICAgY29sb3VyID0gJ3doaXRlJywgCiAgICAgICAgICAgICAgIGZpbGwgPSAnYmxhY2snLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAuNCwgCiAgICAgICAgICAgICAgIHNpemUgPSAuMwogICAgICAgICAgICAgICkKICAKCgoKCgoKWmlwV2FpdFRlc3QgPC0gZmlsdGVyKFNoaW55X1dhaXREYXRhX0Jhc2UsCiAgICAgICAgICAgICAgICAgICAgICBXYWl0VGltZV9NaW4yIDw9IDE4MCAmCiAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShTdG9wX1ppcCkKICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgZ3JvdXBfYnkoU3RvcF9aaXAsCiAgICAgICAgICAgRXZlbnRfVGltZV9IcgogICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKFBjdDgwID0gcXVhbnRpbGUoV2FpdFRpbWVfTWluMiwgcHJvYnMgPSAwLjgsIG5hLnJtID0gVFJVRSkKICAgICAgICAgICApICU+JSAKICBhcnJhbmdlKEV2ZW50X1RpbWVfSHIsCiAgICAgICAgICBTdG9wX1ppcAogICAgICAgICApCgoKVmlldyhoZWFkKFppcFdhaXRUZXN0LCA1MDApKQoKCgoKYGBgCgoKSW52ZXN0aWdhdGluZyBUcmF2ZWxUaW1lX1NlYy4KYGBge3J9CgpWaWV3KGZpbHRlcihUVExhcmdlUnRlQ2huZywKICAgICAgICAgICAgIWlzLm5hKFRyYXZlbFRpbWVfU2VjKSAmCiAgICAgICAgICAgICAgUnRlQ2hhbmdlMiA9PSAiU2FtZSIKICAgICAgICAgICApICU+JSAKICAgICAgIGFycmFuZ2UoZGVzYyhUcmF2ZWxUaW1lX1NlYyksCiAgICAgICAgICAgICAgIFNwZWVkQXZnX01waF9OZXdIdnJzCiAgICAgICAgICAgICAgKSAlPiUKICAgICAgIGhlYWQoNTAwKQogICAgKQoKCiMgZXhhbXBsZXMgd2hlcmUgVHJhdmVsVGltZV9TZWMgaXMgc21hbGwgKDEgc2VjKSBhbmQgU3BlZWRBdmdfTXBoX05ld0h2cnMgaXMgbGFyZ2UuClZpZXcoc2VsZWN0KE5ld1RyYXZUaW1lLAogICAgICAgICAgICAjIC1tYXRjaGVzKCIocSgyfDV8KDk1KXwoOTgpKSl8TWVhbnxNZWR8Q250IikKICAgICAgICAgICAgLShURF9NaV9xMjpURF9NaV9TU0hHX0NudF9GKSwKICAgICAgICAgICAgLShUVF9Icl9xMjpUVF9Icl9TU0hHX0NudF9GKQogICAgICAgICAgICkgJT4lIAogICAgICAgZmlsdGVyKChSb3dOdW1fT0cgPj0gMjIxNzM1MyAmIFJvd051bV9PRyA8PSAyMjE3MzczKSB8ICMgMjIxNzM2MwogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAzMDkwMzIxICYgUm93TnVtX09HIDw9IDMwOTAzNDEpIHwgIyAzMDkwMzMxCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDgwNzY0ICYgUm93TnVtX09HIDw9IDgwNzg0KSB8ICMgODA3NzQKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMzM4NDAgJiBSb3dOdW1fT0cgPD0gMzM4NjApICMgMzM4NTAKICAgICAgICAgICApCiAgICApCgoKCgoKCiMgZXhhbXBsZXMgd2hlcmUgVHJhdmVsVGltZV9TZWMgaXMgbGFyZ2UgYW5kIFNwZWVkQXZnX01waF9OZXdIdnJzIGlzIHNtYWxsLgpWaWV3KGZpbHRlcihUVExhcmdlUnRlQ2huZywKICAgICAgICAgICAgKFJvd051bV9PRyA+PSAyMjUwMjkwICYgUm93TnVtX09HIDw9IDIyNTAzMTApIHwgIyAyMjUwMzAwCiAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSA4Njc3MTcgJiBSb3dOdW1fT0cgPD0gODY3NzM3KSB8ICMgODY3NzI3CiAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSA4NjQzNzkgJiBSb3dOdW1fT0cgPD0gODY0Mzk5KSB8ICMgODY0Mzg5CiAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSA4MDgzOTUgJiBSb3dOdW1fT0cgPD0gODA4NDE1KSAjIDgwODQwNQogICAgICAgICAgICkKICAgICkKYGBgCgoKCgpgYGB7cn0KCiAgICAgICAgIAogICAgICAgICAKIyBleGFtcGxlcyB3aGVyZSBUcmF2ZWxUaW1lX1NlYyBpcyB1bnVzdWFsbHkgc21hbGwgKHdpdGggVHJhdmVsRGlzdGFuY2VfTWkgdmFsdWVzIHRoYXQgYXJlIGxhcmdlKS4KVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAoUm93TnVtX09HID49IDEwNDIyMjggJiBSb3dOdW1fT0cgPD0gMTA0MjI0OCkgfCAjIDEwNDIyMzgKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gNTM4MTYgJiBSb3dOdW1fT0cgPD0gNTM4MzYpIHwgIyA1MzgyNgogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAzNjA1NzEgJiBSb3dOdW1fT0cgPD0gMzYwNTkxKSB8ICMgMzYwNTgxCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDUwMjI3MSAmIFJvd051bV9PRyA8PSA1MDIyOTEpICMgNTAyMjgxIChjYW4ndCBleHBsaWFuIHRoZSB3ZWlyZCBUcmF2ZWxUaW1lX1NlYyBjYWxjdWxhdGlvbiBoZXJlIC0gaXQncyBub3QgZXZlbiBhbiBpbnRlZ2VyISkKICAgICAgICAgICApCiAgICApCgojIHN0aWxsIHRyeWluZyB0byBleHBsYWluIDUwMjI4MS4uLm9uIHRoZSBkYXkgb2YgdGhpcyB3ZWlyZG5lc3MsIHRoZSBidXMgd2FzIG9ubHkgaW4gY2lyY3VsYXRpb24gZm9yIDQtNSBzdG9wcyAofjIwIG1pbnV0ZXMpIG9uIHRoYXQgZGF5IChPY3QgNikKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICBCdXNfSUQgPT0gMjcxMQogICAgICAgICAgICkKICAgICkKCgojIGV4cGxvcmluZyBsYXJnZSB2YWx1ZXMgZm9yIFRyYXZlbFRpbWVfU2VjClZpZXcoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMgPT0gMzAwCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKGRlc2MoVHJhdmVsVGltZV9TZWMpLAogICAgICAgICAgICAgICBTcGVlZEF2Z19NcGgyCiAgICAgICAgICAgICAgKQogICAgKQoKIyBleGFtcGxlcyB3aGVyZSBUcmF2ZWxUaW1lX1NlYyBpcyB1bnVzdWFsbHkgbGFyZ2UgKHdpdGggVHJhdmVsRGlzdGFuY2VfTWkgdmFsdWVzIHRoYXQgYXJlIHNtYWxsLCBzbyBTcGVlZEF2Z19NcGggdmFsdWVzIGFyZSB2ZXJ5IHNtYWxsKS4KVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAoUm93TnVtX09HID49IDI2Mjc0NTkgJiBSb3dOdW1fT0cgPD0gMjYyNzQ3OSkgfCAjIDI2Mjc0NjkKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjE5MzM0NCAmIFJvd051bV9PRyA8PSAyMTkzMzY0KSB8ICMgMjE5MzM1NAogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAxNjQ0MTIzICYgUm93TnVtX09HIDw9IDE2NDQxNDMpIHwgIyAxNjQ0MTMzCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDg2OTYwMCAmIFJvd051bV9PRyA8PSA4Njk2MjApICMgODY5NjEwCiAgICAgICAgICAgKQogICAgKQoKYGBgCgpJbnZlc3RpZ2F0aW9uIG9mIFNwZWVkQXZnX01waDIKClZpZXcoU3BlZWRfUGN0aWxlcyk6IDkwJSBvZiBTcGVlZEF2Z19NcGgyIGFyZSBiZXR3ZWVuIH4zbXBoIGFuZCB+NjZtcGguCmBgYHtyfQoKU3BlZWRfTnRpbGUgPC0gYXMuZGF0YS5mcmFtZShBbGxEYXlzX05ld1RyYXZlbERpc3QkU3BlZWRBdmdfTXBoMikgJT4lIAogIG11dGF0ZShQY3RpbGUgPSBudGlsZShBbGxEYXlzX05ld1RyYXZlbERpc3QkU3BlZWRBdmdfTXBoMiwgMTAwKSwKICAgICAgICAgTWluUiA9IG1pbl9yYW5rKEFsbERheXNfTmV3VHJhdmVsRGlzdCRTcGVlZEF2Z19NcGgyKSwKICAgICAgICAgUGN0UiA9IHBlcmNlbnRfcmFuayhBbGxEYXlzX05ld1RyYXZlbERpc3QkU3BlZWRBdmdfTXBoMiksCiAgICAgICAgIFBjdFJfUm91bmQgPSByb3VuZChQY3RSLCAyKQogICAgICAgICkgCgpjb2xuYW1lcyhTcGVlZF9OdGlsZSlbMV0gPC0gIlNwZWVkQXZnX01waDIiCnN0cihTcGVlZF9OdGlsZSkKClNwZWVkX050aWxlX1Jvd3MgPC0gbnJvdyhTcGVlZF9OdGlsZSkKClZpZXcodGFpbChTcGVlZF9OdGlsZSwgNTAwKSkKCgpTcGVlZF9QY3RpbGVzIDwtIGdyb3VwX2J5KFNwZWVkX050aWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHN1bW1hcmlzZSgKICAgIE1pblNwZWVkQXRQY3RpbGUgPSBtaW4oU3BlZWRBdmdfTXBoMiksCiAgICBDbnRzQXRQY3RpbGUgPSBuKCksCiAgICBQY3RzQXRQY3RpbGUgPSBDbnRzQXRQY3RpbGUgLyBTcGVlZF9OdGlsZV9Sb3dzCiAgKSAlPiUgCiAgbXV0YXRlKEN1bVN1bVBBdFAgPSBjdW1zdW0oUGN0c0F0UGN0aWxlKQogICAgICAgICkKClZpZXcoU3BlZWRfUGN0aWxlcykKCmBgYAoKSW52ZXN0aWdhdGlvbiBvZiBTcGVlZEF2Z19NcGgyLgoKRXhwbG9yaW5nIHRoZSByZW1vdmFsIG9mIG91dGxpZXIgVHJhdmVsVGltZV9TZWMgYW5kIFRyYXZlbERpc3RhbmNlX01pLgpgYGB7cn0KCnN1bW1hcnkoc2VsZWN0KEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgICAgU3BlZWRBdmdfTXBoLAogICAgICAgICAgICAgICBTcGVlZEF2Z19NcGgyCiAgICAgICAgICAgICAgKQogICAgICAgKQoKc3VtbWFyeShzZWxlY3QoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pID4gMC4wMDAxODkzOTM5ICYgIyBsb3dlc3Qgbm9uLXplcm8gcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxEaXN0YW5jZV9NaSA8IDEuMDgxMjUwMDAwMCAmICMgOTl0aCBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjID4gMTAuMDUwMDAwICYgIyAybmQgcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYyA8IDI5My4wMDAwMDAgIyA5OHRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgU3BlZWRBdmdfTXBoLAogICAgICAgICAgICAgICBTcGVlZEF2Z19NcGgyCiAgICAgICAgICAgICAgKQogICAgICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBTcGVlZEF2Z19NcGgyLgoKSGlzdG9ncmFtIG9mIFNwZWVkQXZnX01waDIuCmBgYHtyfQoKU3BlZWRfSGlzdERlbiA8LSBnZ3Bsb3QoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShTcGVlZEF2Z19NcGgyKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IFNwZWVkQXZnX01waDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gLi5kZW5zaXR5Li4KICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNSwgZmlsbCA9ICJsaWdodGJsdWUiLCBjb2xvdXIgPSAiZ3JleTYwIiwgc2l6ZSA9IDAuMikgKwogIGdlb21fbGluZShzdGF0ID0gImRlbnNpdHkiLCBjb2xvdXIgPSAicmVkIikgKwogIHN0YXRfYmluKGJpbndpZHRoID0gNSwKICAgICAgICAgICBnZW9tID0gInRleHQiLAogICAgICAgICAgIHNpemUgPSAyLjUsCiAgICAgICAgICAgdmp1c3QgPSAxLjUsCiAgICAgICAgICAgYWVzKGxhYmVsID0gZm9ybWF0KC4uY291bnQuLiwgYmlnLm1hcmsgPSAiLCIpCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICkgKwogICMgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZvcm1hdCguLmNvdW50Li4sIGJpZy5tYXJrID0gIiwiKQogICMgICAgICAgICAgICAgICksCiAgIyAgICAgICAgICAgc2l6ZSA9IDMsCiAgIyAgICAgICAgICAgbnVkZ2VfeSA9ICguLmNvdW50Li4gKiAwLjEpCiAgIyAgICAgICAgICApICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgNzApLCB5bGltID0gYygwLCAwLjA0KQogICAgICAgICAgICAgICAgICkgKwogICMgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIlZhcmlhdGlvbiBpbiBUcmF2ZWwgU3BlZWQiLAogICAgICAgeCA9ICJBdmVyYWdlIFNwZWVkIChtcGgpIiwKICAgICAgIHkgPSAiRGVuc2l0eSIKICAgICAgKQoKU3BlZWRfSGlzdERlbgoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBTcGVlZEF2Z19NcGgyLgoKSGlzdG9ncmFtIG9mIFNwZWVkQXZnX01waDIgYWZ0ZXIgcmVtb3Zpbmcgb3V0bGllciBUcmF2ZWxUaW1lX1NlYyBhbmQgVHJhdmVsRGlzdGFuY2VfTWkuCmBgYHtyfQoKVmlldyhUcmF2RGlzdE1pTmV3X1BjdGlsZXMpClZpZXcoVHJhdlRpbWVIcl9QY3RpbGVzKQoKU3BlZWROb091dGxpZXJfSGlzdERlbiA8LSBnZ3Bsb3QoZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShTcGVlZEF2Z19NcGgyKSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ldyA+IDAuMDc3ODQxMDA1ICYgIyA1dGggcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFRyYXZlbERpc3RhbmNlX01pX05ldyA8IDEuMDgxMjUwMDAwMCAmICMgOTl0aCBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjID4gMTIuMTAwMDAwICMgNHRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUcmF2ZWxUaW1lX1NlYyA8IDI5My4wMDAwMDAgIyA5OHRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBTcGVlZEF2Z19NcGgyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IC4uZGVuc2l0eS4uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUsIGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3VyID0gImdyZXk2MCIsIHNpemUgPSAwLjIpICsKICBnZW9tX2xpbmUoc3RhdCA9ICJkZW5zaXR5IiwgY29sb3VyID0gInJlZCIpICsKICBzdGF0X2JpbihiaW53aWR0aCA9IDUsCiAgICAgICAgICAgZ2VvbSA9ICJ0ZXh0IiwKICAgICAgICAgICBzaXplID0gMi41LAogICAgICAgICAgIHZqdXN0ID0gMS41LAogICAgICAgICAgIGFlcyhsYWJlbCA9IGZvcm1hdCguLmNvdW50Li4sIGJpZy5tYXJrID0gIiwiKQogICAgICAgICAgICAgICksCiAgICAgICAgICApICsKICAjIGdlb21fdGV4dChhZXMobGFiZWwgPSBmb3JtYXQoLi5jb3VudC4uLCBiaWcubWFyayA9ICIsIikKICAjICAgICAgICAgICAgICApLAogICMgICAgICAgICAgIHNpemUgPSAzLAogICMgICAgICAgICAgIG51ZGdlX3kgPSAoLi5jb3VudC4uICogMC4xKQogICMgICAgICAgICAgKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDcwKSwgeWxpbSA9IGMoMCwgMC4wNCkKICAgICAgICAgICAgICAgICApICsKICAjICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJWYXJpYXRpb24gaW4gVHJhdmVsIFNwZWVkIiwKICAgICAgIHN1YnRpdGxlID0gIihyZW1vdmVkIGxvdyBvdXRsaWVycyBvZiBUcmF2ZWwgRGlzdGFuY2UgYW5kIFRyYXZlbCBUaW1lKSIsCiAgICAgICB4ID0gIkF2ZXJhZ2UgU3BlZWQgKG1waCkiLAogICAgICAgeSA9ICJEZW5zaXR5IgogICAgICApCgpTcGVlZE5vT3V0bGllcl9IaXN0RGVuCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFNwZWVkQXZnX01waDIuCgpOZXcgZGF0YXNldCAoTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUpIHdoZW4gcmVtb3Zpbmcgb3V0bGllciBsb3cgdmFsdWVzIG9mIFRyYXZlbERpc3RhbmNlX01pX05ldyBhbmQgVHJhdmVsVGltZV9TZWMuCmBgYHtyfQoKVmlldyhUcmF2RGlzdE1pTmV3X1BjdGlsZXMpClZpZXcoVHJhdlRpbWVIcl9QY3RpbGVzKQoKTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUgPC0gZmlsdGVyKEFsbERheXNfTmV3VHJhdmVsRGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbERpc3RhbmNlX01pX05ldyA+IC4wNzc4NDEwMDUgJiAjIDV0aCBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVHJhdmVsRGlzdGFuY2VfTWlfTmV3IDwgMS4wODEyNTAwMDAwICYgIyA5OXRoIHBlcmNlbnRpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMgPiAxMi4xMDAwMDAgIyA0dGggcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFRyYXZlbFRpbWVfU2VjIDwgMjkzLjAwMDAwMCAjIDk4dGggcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCgpucm93KEFsbERheXNfTmV3VHJhdmVsRGlzdCkgLSBucm93KE5vT3V0bGllcnNfVHJhdmVsRGlzdE5UaW1lKQoKc3RyKE5vT3V0bGllcnNfVHJhdmVsRGlzdE5UaW1lKQpzdW1tYXJ5KE5vT3V0bGllcnNfVHJhdmVsRGlzdE5UaW1lKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBTcHBlZEF2Z19NcGgyLgoKVmlldyhTcGVlZF9Ob091dF9QY3RpbGVzKTogIEFwcm94aW1hdGVseSA5MCUgb2YgU3BlZWRBdmdfTXBoMiB2YWx1ZXMgYXJlIGJldHdlZW4gfjRtcGggYW5kIH41Nm1waC4KYGBge3J9CgpTcGVlZF9Ob091dF9OdGlsZSA8LSBhcy5kYXRhLmZyYW1lKE5vT3V0bGllcnNfVHJhdmVsRGlzdE5UaW1lJFNwZWVkQXZnX01waDIpICU+JSAKICBtdXRhdGUoUGN0aWxlID0gbnRpbGUoTm9PdXRsaWVyc19UcmF2ZWxEaXN0TlRpbWUkU3BlZWRBdmdfTXBoMiwgMTAwKSwKICAgICAgICAgTWluUiA9IG1pbl9yYW5rKE5vT3V0bGllcnNfVHJhdmVsRGlzdE5UaW1lJFNwZWVkQXZnX01waDIpLAogICAgICAgICBQY3RSID0gcGVyY2VudF9yYW5rKE5vT3V0bGllcnNfVHJhdmVsRGlzdE5UaW1lJFNwZWVkQXZnX01waDIpLAogICAgICAgICBQY3RSX1JvdW5kID0gcm91bmQoUGN0UiwgMikKICAgICAgICApIAoKY29sbmFtZXMoU3BlZWRfTm9PdXRfTnRpbGUpWzFdIDwtICJTcGVlZEF2Z19NcGgyIgpzdHIoU3BlZWRfTm9PdXRfTnRpbGUpCgpTcGVlZF9Ob091dF9OdGlsZV9Sb3dzIDwtIG5yb3coU3BlZWRfTm9PdXRfTnRpbGUpCgpWaWV3KHRhaWwoU3BlZWRfTm9PdXRfTnRpbGUsIDUwMCkpCgoKU3BlZWRfTm9PdXRfUGN0aWxlcyA8LSBncm91cF9ieShTcGVlZF9Ob091dF9OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQY3RSX1JvdW5kCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzdW1tYXJpc2UoCiAgICBNaW5TcGVlZEF0UGN0aWxlID0gbWluKFNwZWVkQXZnX01waDIpLAogICAgQ250c0F0UGN0aWxlID0gbigpLAogICAgUGN0c0F0UGN0aWxlID0gQ250c0F0UGN0aWxlIC8gU3BlZWRfTm9PdXRfTnRpbGVfUm93cwogICkgJT4lIAogIG11dGF0ZShDdW1TdW1QQXRQID0gY3Vtc3VtKFBjdHNBdFBjdGlsZSkKICAgICAgICApCgpWaWV3KFNwZWVkX05vT3V0X1BjdGlsZXMpCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIFNwcGVkQXZnX01waDIuCgpFeGxvcmluZyBvZGQvaW1wb3NzaWJsZSB2YWx1ZXMuCmBgYHtyfQoKIyBFeHBsb3Jpbmcgd2hlbiBTcGVlZEF2Z19NcGgyIGlzIE5BICAtLSAgZG9lcyBub3Qgb2NjdXIgYXQgYWxsCm5yb3coZmlsdGVyKE5vT3V0bGllcnNfVHJhdmVsRGlzdE5UaW1lLAogICAgICAgICAgICBpcy5uYShTcGVlZEF2Z19NcGgyKQogICAgICAgICAgICkKICAgICkKCgojIEV4cGxvcmluZyB3aGVuIFNwZWVkQXZnX01waDIgaXMgemVybyAgLS0gIGRvZXMgbm90IG9jY3VyIGF0IGFsbApucm93KGZpbHRlcihOb091dGxpZXJzX1RyYXZlbERpc3ROVGltZSwKICAgICAgICAgICAgU3BlZWRBdmdfTXBoMiA9PSAwCiAgICAgICAgICAgKQogICAgKQoKCiMgZXhhbXBsZXMgd2hlcmUgU3BlZWRBdmdfTXBoMiA8IDMuMjg0ODc3MApWaWV3KGZpbHRlcihBbGxEYXlzX05ld1RyYXZlbERpc3QsCiAgICAgICAgICAgIFNwZWVkQXZnX01waDIgPiAwICYKICAgICAgICAgICAgICBTcGVlZEF2Z19NcGgyIDwgMy4yODQ4NzcwCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKFNwZWVkQXZnX01waDIpCiAgICApCgojIGV4YW1wbGVzIHdoZXJlIFNwZWVkQXZnX01waDIgPCAzLjI4NDg3NzAKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdUcmF2ZWxEaXN0LAogICAgICAgICAgICAoUm93TnVtX09HID49IDQ4NTMzOCAmIFJvd051bV9PRyA8PSA0ODUzNTgpIHwgIyA0ODUzNDggIC0tICBFeHRyZW1lIHRyYXZlbCB0aW1lLCBSb3V0ZSBDaGFuZ2UKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMzQ2OTUyICYgUm93TnVtX09HIDw9IDM0Njk3MikgfCAjIDM0Njk2MiAgLS0gRXh0cmVtZSB0cmF2ZWwgdGltZSwgUm91dGUgQ2hhbmdlIAogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSA3MDQ5NCAmIFJvd051bV9PRyA8PSA3MDUxNCkgfCAjIDcwNTA0ICAtLSAgRXh0cmVtZSB0cmF2ZWwgdGltZSwgUm91dGUgQ2hhbmdlCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDIwNTE4NDYgJiBSb3dOdW1fT0cgPD0gMjA1MTg2NikgIyAyMDUxODU2ICAtLSAgRXh0cmVtZSB0cmF2ZWwgdGltZSwgUm91dGUgQ2hhbmdlCiAgICAgICAgICAgKQogICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBTcGVlZEF2Z19NcGgyLgoKTGltaXQgdGhlIGRhdGFzZXQgYmFzZWQgb24gU3BlZWRBdmdfTXBoMi4KYGBge3J9CgpOb091dGxpZXJzU3BlZWQgPC0gZmlsdGVyKE5vT3V0bGllcnNfVHJhdmVsRGlzdE5UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgIGJldHdlZW4oU3BlZWRBdmdfTXBoMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDQuMDY5MzAwLCAjIDV0aCBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA1Ni4wNTY1MSAjOTV0aCBwZXJjZW50aWxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICApCgpucm93KE5vT3V0bGllcnNfVHJhdmVsRGlzdE5UaW1lKSAtIG5yb3coTm9PdXRsaWVyc1NwZWVkKQoKc3VtbWFyeShOb091dGxpZXJzU3BlZWQpCgpgYGAKCgpUcmF2ZWxUaW1lIG5vdyBsb29rcyBsaWtlIGl0IGhhcyBzb21lIG9kZCB2YWx1ZXMgb24gdGhlIGhpZ2ggZW5kLiAgU28gbGV0J3MgbG9vayBhdCB0aG9zZS4KClZpZXcoVHJhdlRpbWVfTm9PdXRfUGN0aWxlcyk6ICBWaXJ0dWFsbHkgYWxsIHRyaXBzIHNob3VsZCB0YWtlIGxlc3MgdGhhbiA1IG1pbnV0ZXMuIChUaGUgOTl0aCBwZXJjZW50aWxlIG9mIG9mIFRyYXZlbFRpbWUgaXMgYXBwcm94aW1hdGVseSA4IG1pbnV0ZXMuKQpgYGB7cn0KClRyYXZUaW1lX05vT3V0X050aWxlIDwtIGFzLmRhdGEuZnJhbWUoTm9PdXRsaWVyc1NwZWVkJFRyYXZlbFRpbWVfSHIpICU+JSAKICBtdXRhdGUoUGN0aWxlID0gbnRpbGUoTm9PdXRsaWVyc1NwZWVkJFRyYXZlbFRpbWVfSHIsIDEwMCksCiAgICAgICAgIE1pblIgPSBtaW5fcmFuayhOb091dGxpZXJzU3BlZWQkVHJhdmVsVGltZV9IciksCiAgICAgICAgIFBjdFIgPSBwZXJjZW50X3JhbmsoTm9PdXRsaWVyc1NwZWVkJFRyYXZlbFRpbWVfSHIpLAogICAgICAgICBQY3RSX1JvdW5kID0gcm91bmQoUGN0UiwgMikKICAgICAgICApCgpjb2xuYW1lcyhUcmF2VGltZV9Ob091dF9OdGlsZSlbMV0gPC0gIlRyYXZlbFRpbWVfSHIiCnN0cihUcmF2VGltZV9Ob091dF9OdGlsZSkKClRyYXZUaW1lX05vT3V0X050aWxlX1Jvd3MgPC0gbnJvdyhUcmF2VGltZV9Ob091dF9OdGlsZSkKClZpZXcodGFpbChUcmF2VGltZV9Ob091dF9OdGlsZSwgNTAwKSkKCgpUcmF2VGltZV9Ob091dF9QY3RpbGVzIDwtIGdyb3VwX2J5KFRyYXZUaW1lX05vT3V0X050aWxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHN1bW1hcmlzZSgKICAgIE1pblRyYXZUaW1lSHJBdFBjdGlsZSA9IG1pbihUcmF2ZWxUaW1lX0hyKSwKICAgIENudHNBdFBjdGlsZSA9IG4oKSwKICAgIFBjdHNBdFBjdGlsZSA9IENudHNBdFBjdGlsZSAvIFRyYXZUaW1lX05vT3V0X050aWxlX1Jvd3MKICApICU+JSAKICBtdXRhdGUoQ3VtU3VtUEF0UCA9IGN1bXN1bShQY3RzQXRQY3RpbGUpLAogICAgICAgICBNaW5UcmF2VGltZVNlY0F0UGN0aWxlID0gTWluVHJhdlRpbWVIckF0UGN0aWxlICogKDYwICogNjApCiAgICAgICAgKQoKVmlldyhUcmF2VGltZV9Ob091dF9QY3RpbGVzKQoKYGBgCgoKSW52ZXN0aWdhdGluZyBvZGQgVHJhdmVsVGltZV9TZWMgdmFsdWVzLgoKVHJpcHMgbG9uZ2VyIHRoYW4gfjggbWludXRlcy4KYGBge3J9CgpWaWV3KGZpbHRlcihOb091dGxpZXJzU3BlZWQsCiAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjID4gNDkxICMgbWluIGF0IHRoZSAxMDB0aCBwZXJjZW50aWxlCiAgICAgICAgICAgKSAlPiUgCiAgICAgICBhcnJhbmdlKGRlc2MoVHJhdmVsVGltZV9TZWMpCiAgICAgICAgICAgICAgKQogICAgKQoKIyBleGFtcGxlcyBvZiBUcmF2ZWxUaW1lX1NlYyB2YWx1ZXMgdGhhdCBhcmUgbGFyZ2VzdC4KVmlldyhmaWx0ZXIoTm9PdXRsaWVyc1NwZWVkLAogICAgICAgICAgICAoUm93TnVtX09HID49IDIwNzE3NTkgJiBSb3dOdW1fT0cgPD0gMjA3MTc3OSkgfCAjIDIwNzE3NjkgIC0tICByZXN1bHRzIGZyb20gYSByb3V0ZSBjaGFuZ2UsIGFuZCBhIDNocisgd2FpdCBiZWZvcmUgdGhlIG5ldyByb3V0ZSBzdGFydHMKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMTQ3MzY4NiAmIFJvd051bV9PRyA8PSAxNDczNzA2KSB8ICMgMTQ3MzY5NiAgLS0gIHJlc3VsdHMgZnJvbSBhIHJvdXRlIGNoYW5nZSwgYW5kIGEgM2hyIHdhaXQgYmVmb3JlIHRoZSBuZXcgcm91dGUgc3RhcnRzCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDEyMjI4MjIgJiBSb3dOdW1fT0cgPD0gMTIyMjg0MikgfCAjIDEyMjI4MzIgIC0tICByZXN1bHRzIGZyb20gYSByb3V0ZSBjaGFuZ2UsIGFuZCBhIDNociB3YWl0IGJlZm9yZSB0aGUgbmV3IHJvdXRlIHN0YXJ0cwogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAzMDQ2MDg5ICYgUm93TnVtX09HIDw9IDMwNDYxMDkpICMgMzA0NjA5OSAgLS0gIHJlc3VsdHMgZnJvbSBhIHJvdXRlIGNoYW5nZSwgYW5kIGEgM2hyIHdhaXQgYmVmb3JlIHRoZSBuZXcgcm91dGUgc3RhcnRzCiAgICAgICAgICAgKQogICAgKQoKCiMgZXhhbXBsZXMgb2YgVHJhdmVsVGltZV9TZWMgdmFsdWVzIHRoYXQgYXJlIHRoZSBzbWFsbGVzdCBvZiB0aGUgbGFyZ2UuClZpZXcoZmlsdGVyKE5vT3V0bGllcnNTcGVlZCwKICAgICAgICAgICAgKFJvd051bV9PRyA+PSAzMDQ0Njg5ICYgUm93TnVtX09HIDw9IDMwNDQ3MDkpIHwgIyAzMDQ0Njk5ICAtLSAgcmVzdWx0cyBmcm9tIGEgcm91dGUgY2hhbmdlCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDMwMjIzNTggJiBSb3dOdW1fT0cgPD0gMzAyMjM3OCkgfCAjIDMwMjIzNjggIC0tICByZXN1bHRzIGZyb20gYSByb3V0ZSBjaGFuZ2UKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjk5MzAxNiAmIFJvd051bV9PRyA8PSAyOTkzMDM2KSB8ICMgMjk5MzAyNiAgLS0gIHJlc3VsdHMgZnJvbSBhIHByZXZpb3VzIHJvdXRlIGNoYW5nZSAoY2hhbmdlIG9jY3VycmVkIGluIGRlbGV0ZWQgcm93KQogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAyNjgzNzAzICYgUm93TnVtX09HIDw9IDI2ODM3MjMpICMgMjY4MzcxMyAgLS0gIHJlc3VsdHMgZnJvbSBhIHByZXZpb3VzIHJvdXRlIGNoYW5nZSAoY2hhbmdlIG9jY3VycmVkIGluIGRlbGV0ZWQgcm93KQogICAgICAgICAgICkKICAgICkKCmBgYAoKCkxldCdzIGxvb2sgYXQgdGhlIFRyYXZlbFRpbWVfU2VjIHZhbHVlcyBhbmQgcm91dGUgY2hhbmdlcyAoRGlyQ2hhbmdlMikuCgpUaGUgOTl0aCBwZXJjZW50aWxlIG9mIFRyYXZlbFRpbWVfU2VjIGZvciBib3RoLCBhbGwgdHJpcHMsIGFuZCBqdXN0IHRob3NlIHRyaXBzIE5PVCBpbnZvbHZpbmcgcm91dGUgY2hhbmdlcyAoRGlyQ2hhbmdlMiA9ICJTYW1lIiksIGlzIGFwcHJveGltYXRlbHkgNW1pbiAoMzAwIHNlYykuCgpOb3RhIEJlbmU6ICBUaGUgcGVyY2VudGlsZSBjYWxjdWxhdGlvbiBoZXJlIGlzIGRlZmluZWQgc2xpZ2h0bHkgZGlmZmVyZW50IHRoYW4gaW4gbW9zdCBvZiB0aGUgYWJvdmUgYW5hbHlzZXMgKHdoaWNoIGdldCB0aGUgbG93ZXN0IHZhbHVlIGluIHRoZSBiaW4gY3JlYXRlZCBieSAxMDAgbnRpbGVzKS4KYGBge3J9CgpzdW1tYXJ5KHNlbGVjdChOb091dGxpZXJzU3BlZWQsCiAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjCiAgICAgICAgICAgICAgKQogICAgICAgKQoKc3VtbWFyeShzZWxlY3QoZmlsdGVyKE5vT3V0bGllcnNTcGVlZCwKICAgICAgICAgICAgICAgICAgICAgIERpckNoYW5nZTIgPT0gIlNhbWUiCiAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjCiAgICAgICAgICAgICAgKQogICAgICAgKQoKc3VtbWFyeShzZWxlY3QoZmlsdGVyKE5vT3V0bGllcnNTcGVlZCwKICAgICAgICAgICAgICAgICAgICAgIERpckNoYW5nZTIgPT0gIkNoYW5nZSIKICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgVHJhdmVsVGltZV9TZWMKICAgICAgICAgICAgICApCiAgICAgICApCgoKVHJhdlRpbWVTZWNfUXRpbGVzX2RmIDwtIGRhdGEuZnJhbWUoUGN0VmFsdWUgPSBzZXEoMCwgMTAwLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQWxsID0gc2VxKDEsIDEwMSwgMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNhbWUgPSBzZXEoMSwgMTAxLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ2hhbmdlID0gc2VxKDEsIDEwMSwgMSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCgpUcmF2VGltZVNlY19RdGlsZXNfZGZbICwgMl0gPC0gcXVhbnRpbGUoc2VsZWN0KE5vT3V0bGllcnNTcGVlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2JzID0gc2VxKDAsIDEsIDAuMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKClRyYXZUaW1lU2VjX1F0aWxlc19kZlsgLCAzXSA8LSBxdWFudGlsZShzZWxlY3QoZmlsdGVyKE5vT3V0bGllcnNTcGVlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGlyQ2hhbmdlMiA9PSAiU2FtZSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYnMgPSBzZXEoMCwgMSwgMC4wMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKVHJhdlRpbWVTZWNfUXRpbGVzX2RmWyAsIDRdIDwtIHF1YW50aWxlKHNlbGVjdChmaWx0ZXIoTm9PdXRsaWVyc1NwZWVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEaXJDaGFuZ2UyID09ICJDaGFuZ2UiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUcmF2ZWxUaW1lX1NlYwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2JzID0gc2VxKDAsIDEsIDAuMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKClZpZXcoVHJhdlRpbWVTZWNfUXRpbGVzX2RmKQoKYGBgCgoKTGltaXQgdGhlIGRhdGFzZXQgbm93IGJhc2VkIG9uIFRyYXZlbFRpbWVfU2VjLgpgYGB7cn0KClVwcGVyTGltaXRUcmF2VGltZSA8LSBmaWx0ZXIoTm9PdXRsaWVyc1NwZWVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyYXZlbFRpbWVfU2VjIDw9IDQ5MSAjIG1pbiBhdCB0aGUgMTAwdGggcGVyY2VudGlsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCm5yb3coTm9PdXRsaWVyc1NwZWVkKSAtIG5yb3coVXBwZXJMaW1pdFRyYXZUaW1lKQoKc3RyKFVwcGVyTGltaXRUcmF2VGltZSkKCnN1bW1hcnkoVXBwZXJMaW1pdFRyYXZUaW1lKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBEd2VsbF9UaW1lMiAoaG93IGxvbmcgdGhlIGJ1cyBpcyBhdCBhIHN0b3ApLgoKRGlmZmVyZW5jZXMgYmV0d2VlbiBEd2VsbF9UaW1lIChieSBXTUFUQSkgYW5kIER3ZWxsX1RpbWUyIChieSBtZSkgYXBwZWFyIHRvIGJlIGR1ZSB0byBzd2l0Y2hlcyBpbiBSb3V0ZUFsdC4gV01BVEEgY2FsY3VsYXRlcyBEd2VsbF9UaW1lIGJ5IGFuIHVua25vd24gcHJvY2Vzcy4gVGhlIFdNQVRBIGNhbGN1bGF0aW9uIGlzIGVxdWFsIHRvIG15IGNhbGN1bGF0aW9uLCBleGNlcHQgZm9yIHRoZSByZWNvcmRzIGltbWVkYWl0ZWx5IGJlZm9yZSBhbmQgYWZ0ZXIgYSBSb3V0ZUFsdCBzd2l0Y2ggKERpckNoYW5nZTIpLgpgYGB7cn0KClZpZXcoZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgIER3ZWxsX1RpbWUgIT0gRHdlbGxfVGltZTIKICAgICAgICAgICApCiAgICApCgoKIyBFeGFtcGxlcyB3aGVyZSB0aGUgRHdlbGxfVGltZSBhbmQgRHdlbGxfVGltZTIgYXJlIGRpZmZlcmVudApWaWV3KGZpbHRlcihBbGxEYXlzX05ld09yZGVyLAogICAgICAgICAgICAoIChSb3dOdW1fT0cgPj0gNjUgJiBSb3dOdW1fT0cgPD0gODUpIHwgIyA3NQogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSAxNjIgJiBSb3dOdW1fT0cgPD0gMTkyKSB8ICMgMTcyCiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDQzMTk1MiAmIFJvd051bV9PRyA8PSA0MzE5NzIpIHwgIyA0MzE5NjIKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gNDM0NTk1ICYgUm93TnVtX09HIDw9IDQzNDYxNSkgIyA0MzQ2MDUgIC0tICB0aGlzIHJlY29yZCBpcyBOT1QgYSByb3V0ZSBzd2l0Y2gsIGJ1dCBkb2VzIGhhcyBhIFNlcXVlbmNlIHN3aXRjaCAoTWU6IHNob3VsZCB0aGVyZSByZWFsbHkgYmUgYSByb3V0ZSBzd2l0Y2ggaGVyZT8pCiAgICAgICAgICAgICkKICAgICAgICAgICApCiAgICApCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIER3ZWxsX1RpbWUyIChob3cgbG9uZyB0aGUgYnVzIGlzIGF0IGEgc3RvcCkuCgpGaXJzdCwgY3JlYXRlIHNvbWUgInJhbmsiIHN0YXRzLgpWaWV3KERUMl9QY3RpbGVzKTogOTUlIG9mIER3ZWxsX1RpbWUycyBhcmUgPD0gMjMgc2Vjb25kcy4uLmJ1dCBzb21lIHdlaXJkIChlLmcuLCBuZWFybHkgMiBob3VyIER3ZWxsX1RpbWUycyBleGlzdCkuCmBgYHtyfQoKRHdlbGxUaW1lMl9OdGlsZSA8LSBhcy5kYXRhLmZyYW1lKEFsbERheXNfTmV3T3JkZXIkRHdlbGxfVGltZTIpICU+JSAKICBtdXRhdGUoUGN0aWxlID0gbnRpbGUoQWxsRGF5c19OZXdPcmRlciREd2VsbF9UaW1lMiwgMTAwKSwKICAgICAgICAgTWluUiA9IG1pbl9yYW5rKEFsbERheXNfTmV3T3JkZXIkRHdlbGxfVGltZTIpLAogICAgICAgICBQY3RSID0gcGVyY2VudF9yYW5rKEFsbERheXNfTmV3T3JkZXIkRHdlbGxfVGltZTIpLAogICAgICAgICBQY3RSX1JvdW5kID0gcm91bmQoUGN0UiwgMikKICAgICAgICApIAoKY29sbmFtZXMoRHdlbGxUaW1lMl9OdGlsZSlbMV0gPC0gIkR3ZWxsX1RpbWUyIgpzdHIoRHdlbGxUaW1lMl9OdGlsZSkKCkR3ZWxsVGltZTJfTnRpbGVfUm93cyA8LSBucm93KER3ZWxsVGltZTJfTnRpbGUpCgpWaWV3KHRhaWwoRHdlbGxUaW1lMl9OdGlsZSwgNTAwKSkKCgpEd2VsbFRpbWUyX1BjdGlsZXMgPC0gZ3JvdXBfYnkoRHdlbGxUaW1lMl9OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdFJfUm91bmQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgTWluRHdlbGxBdFBjdGlsZSA9IG1pbihEd2VsbF9UaW1lMiksCiAgICBDbnRzQXRQY3RpbGUgPSBuKCksCiAgICBQY3RzQXRQY3RpbGUgPSBDbnRzQXRQY3RpbGUgLyBEd2VsbFRpbWUyX050aWxlX1Jvd3MKICApICU+JSAKICBtdXRhdGUoQ3VtU3VtUEF0UCA9IGN1bXN1bShQY3RzQXRQY3RpbGUpCiAgICAgICAgKQoKVmlldyhEd2VsbFRpbWUyX1BjdGlsZXMpCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIER3ZWxsX1RpbWUyIChob3cgbG9uZyB0aGUgYnVzIGlzIGF0IGEgc3RvcCkuCgpIaXN0b2dyYW0gb2YgRHdlbGxfVGltZTIuCmBgYHtyfQoKRHdlbGxUaW1lMl9IaXN0RGVuIDwtIGdncGxvdChBbGxEYXlzX05ld09yZGVyLCBhZXMoeCA9IER3ZWxsX1RpbWUyLCB5ID0gLi5kZW5zaXR5Li4pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG91ciA9ICJncmV5NjAiLCBzaXplID0gMC4yKSArCiAgZ2VvbV9saW5lKHN0YXQgPSAiZGVuc2l0eSIsIGNvbG91ciA9ICJyZWQiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDEsIDI1KSwgeWxpbSA9IGMoMCwgMC4wNSkKICAgICAgICAgICAgICAgICApICsKICB4bGFiKCJUaW1lIGEgQnVzIFN0YXlzIGF0IGEgU3RvcCAoc2VjKSIpICsgCiAgeWxhYigiRGVuc2l0eSIpICsgCiAgIyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyAKICBnZ3RpdGxlKGV4cHJlc3Npb24oYXRvcCgiVmFyaWF0aW9uIGluIEhvdyBMb25nIGEgQnVzIFN0YXlzIGF0IGEgU3RvcCIKICAgICAgICAgICAgICAgICAgICAgICAgICAjICxhdG9wKGl0YWxpYygieHh4eHgiKSwiIikKICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICkKCkR3ZWxsVGltZTJfSGlzdERlbgoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBEd2VsbF9UaW1lMiAoaG93IGxvbmcgdGhlIGJ1cyBpcyBhdCBhIHN0b3ApLgoKTG9va2luZyBhdCBzb21lIHdlaXJkbHkgbG9uZyBEd2VsbF9UaW1lMiB2YWx1ZXMuCmBgYHtyfQoKVmlldyhhcnJhbmdlKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICBkZXNjKER3ZWxsX1RpbWUyKQogICAgICAgICAgICApCiAgICApCgoKIyBleGFtcGxlcyBvZiBleHRyZW1lbHkgbGFyZ2UgRHdlbGxfVGltZTJzClZpZXcoZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMjkyNjY5ICYgUm93TnVtX09HIDw9IDI5MjY4OSkgfCAjIDI5MjY3OQogICAgICAgICAgICAgICAgKFJvd051bV9PRyA+PSA1MzEwNTcgJiBSb3dOdW1fT0cgPD0gNTMxMDc3KSB8ICMgNTMxMDY3CiAgICAgICAgICAgICAgICAoUm93TnVtX09HID49IDEzODg2MjcgJiBSb3dOdW1fT0cgPD0gMTM4ODY0NykgfCAjIDEzODg2MzcKICAgICAgICAgICAgICAgIChSb3dOdW1fT0cgPj0gMTY0NTcxMSAmIFJvd051bV9PRyA8PSAxNjQ1NzMxKSAjIDE2NDU3MjEKICAgICAgICAgICApCiAgICApCgoKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgRHdlbGxfVGltZTIgPT0gMAogICAgICAgICAgICkKICAgICkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgRGVsdGFfVGltZSAoaG93IGVhcmx5IG9yIGxhdGUgdGhlIGJ1cyBpcykuCgpWaWV3KERUMl9QY3RpbGVzKTogOTQlIG9mIERlbHRhX1RpbWUgdmFsdWVzIGFyZSBiZXR3ZWVuIC0yMzYgc2Vjb25kcyBhbmQgMSwyNTkgc2Vjb25kcy4gUm91Z2hseSA2NiUgb2YgcmVjb3JkcyBhcmUgd2l0aGluIDUgbWluIGxhdGUgYW5kIDUgbWluIGVhcmx5Li4uYnV0IHNvbWUgd2VpcmQgKGUuZy4sIGFsbW9zdCA1MCBtaW51dGUgbGF0ZSBvciA0MCBtaW51dGUgZWFybHkpIERlbHRhX1RpbWVzIGV4aXN0LgoKTm90ZSB0aGF0IERlbHRhX1RpbWUgaXMgdGhlIGRpZmZlcmVuY2UgZnJvbSB0aGUgc2NoZWR1bGVkIGJ1cyBhcnJpdmFsLiBTbyBpZiB0d28gYnVzZXMgYXJlIHNjaGVkdWxlZCB0byBhcnJpdmUgYXQgYSBkZXN0aW5hdGlvbiBhdCAxMDowMHBtIGFuZCAxMDoyMHBtLCBhbmQgaWYgdGhlIDEwOjIwcG0gYnVzIGhhcyBhIERlbHRhX1RpbWUgb2YgNSBtaW51dGVzLCB0aGVyZSBhcmUgMjUgbWludXRlcyBiZXR3ZWVuIGJ1cyBhcnJpdmFscyBhdCB0aGUgc3RvcC4KCkFsc28gbm90ZSB0aGF0IGJhc2VkIG9uIGEgY29tbWVudCBhdCBodHRwczovL3BsYW5pdG1ldHJvLmNvbS8yMDE2LzExLzE2L2RhdGEtZG93bmxvYWQtbWV0cm9idXMtdmVoaWNsZS1sb2NhdGlvbi1kYXRhLywgdGhlIERlbHRhX1RpbWUgdmFsdWVzIGRvbid0IGFwcGVhciB0byBjb2luY2lkZSB3aXRoIHB1Ymxpc2hlZCBidXMgc2NoZWR1bGVzIChlLmcuLCB0aGUgWDIgZGVwYXJ0aW5nIGV2ZXJ5IDggbWludXRlcyBkdXJpbmcgcGVhayBob3VycykuCmBgYHtyfQoKRGVsdFRpbWVfTnRpbGUgPC0gYXMuZGF0YS5mcmFtZShBbGxEYXlzX05ld09yZGVyJERlbHRhX1RpbWUpICU+JSAKICBtdXRhdGUoUGN0aWxlID0gbnRpbGUoQWxsRGF5c19OZXdPcmRlciREZWx0YV9UaW1lLCAxMDApLAogICAgICAgICBNaW5SID0gbWluX3JhbmsoQWxsRGF5c19OZXdPcmRlciREZWx0YV9UaW1lKSwKICAgICAgICAgUGN0UiA9IHBlcmNlbnRfcmFuayhBbGxEYXlzX05ld09yZGVyJERlbHRhX1RpbWUpLAogICAgICAgICBQY3RSX1JvdW5kID0gcm91bmQoUGN0UiwgMikKICAgICAgICApIAoKY29sbmFtZXMoRGVsdFRpbWVfTnRpbGUpWzFdIDwtICJEZWx0YV9UaW1lIgpzdHIoRGVsdFRpbWVfTnRpbGUpCgpEZWx0VGltZV9OdGlsZV9Sb3dzIDwtIG5yb3coRGVsdFRpbWVfTnRpbGUpCgpWaWV3KHRhaWwoRGVsdFRpbWVfTnRpbGUsIDUwMCkpCgoKRGVsdFRpbWVfUGN0aWxlcyA8LSBncm91cF9ieShEZWx0VGltZV9OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQY3RSX1JvdW5kCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzdW1tYXJpc2UoCiAgICBNaW5EZWx0VGltZUF0UGN0aWxlID0gbWluKERlbHRhX1RpbWUpLAogICAgQ250c0F0UGN0aWxlID0gbigpLAogICAgUGN0c0F0UGN0aWxlID0gQ250c0F0UGN0aWxlIC8gRGVsdFRpbWVfTnRpbGVfUm93cwogICkgJT4lIAogIG11dGF0ZShDdW1TdW1QQXRQID0gY3Vtc3VtKFBjdHNBdFBjdGlsZSkKICAgICAgICApCgpWaWV3KERlbHRUaW1lX1BjdGlsZXMpCkRlbHRUaW1lX1BjdGlsZXMKCiMgfjY2JSBvZiByb3dzIGFyZSBiZXR3ZWVuIDUgbWluIGxhdGUgYW5kIDUgbWluIGVhcmx5Cm5yb3coZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgIERlbHRhX1RpbWUgPj0gLTMwMCAmCiAgICAgICAgICAgICAgRGVsdGFfVGltZSA8PSAzMDAKICAgICAgICAgICApCiAgICApIC8gbnJvdyhBbGxEYXlzX05ld09yZGVyKQoKCiMgZXhhbXBsZXMgb2Ygd2VpcmQgbGFyZ2UgRGVsdGFfVGltZXMKVmlldyhmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgRGVsdGFfVGltZSA8IC00MjAyIHwKICAgICAgICAgICAgICBEZWx0YV9UaW1lID4gMTcwNQogICAgICAgICAgICkgJT4lIAogICAgICAgYXJyYW5nZShkZXNjKERlbHRhX1RpbWUpCiAgICAgICAgICAgICAgKQogICAgKQoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBEZWx0YV9UaW1lIChob3cgZWFybHkgb3IgbGF0ZSB0aGUgYnVzIGlzKS4KCkRlbHRhX1RpbWUgaGlzdG9ncmFtLgpgYGB7cn0KCkRlbHRUaW1lX0hpc3REZW4gPC0gZ2dwbG90KEFsbERheXNfTmV3T3JkZXIsIGFlcyh4ID0gKERlbHRhX1RpbWUgLyA2MCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gLi5kZW5zaXR5Li4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gKDUvNjApLCBmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG91ciA9ICJncmV5NjAiLCBzaXplID0gMC4yKSArCiAgZ2VvbV9saW5lKHN0YXQgPSAiZGVuc2l0eSIsIGNvbG91ciA9ICJyZWQiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKC01LCA1KSkgKwogIHhsYWIoIkJ1cyBMYXRlbmVzcyAobWluKSIpICsgCiAgeWxhYigiRGVuc2l0eSIpICsgCiAgIyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyAKICBnZ3RpdGxlKGV4cHJlc3Npb24oYXRvcCgiVmFyaWF0aW9uIGluIEhvdyBFYXJseS9MYXRlIGEgQnVzIElzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBhdG9wKGl0YWxpYygiKHBvc2l0aXZlIHZhbHVlcyBhcmUgbGF0ZSBhcnJpdmFscykiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICkKCkRlbHRUaW1lX0hpc3REZW4KCmBgYAoKCkludmVzdGlnYXRpb24gb2YgRGVsdGFfVGltZSAoaG93IGVhcmx5IG9yIGxhdGUgdGhlIGJ1cyBpcykuCgpEZWx0YV9UaW1lIGJveHBsb3QuCmBgYHtyfQoKIyBDb3VudF9WYWx1ZXMgaXMgbmVlZGVkIHRvIGRpc3BsYXkgdGhlIG1lZGlhbnMgb24gdGhlIGJveCBwbG90cwpDb3VudF9WYWx1ZXMgPC0gZGRwbHkoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgICAgICAgICAgIC4oRXZlbnRfVGltZV9Ickdyb3VwKSwKICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSwKICAgICAgICAgICAgICAgICAgICAgIFZhbHVlX0NvdW50cyA9IG1lZGlhbihEZWx0YV9UaW1lIC8gNjAsIG5hLnJtID0gVFJVRSkKICAgICAgICAgICAgICAgICAgICAgKQoKRGVsdFRpbWVfQm94UGxvdCA8LSBnZ3Bsb3QoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGZhY3RvcihFdmVudF9UaW1lX0hyR3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVsdGFfVGltZSAvIDYwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGZhY3RvcihFdmVudF9UaW1lX0hyR3JvdXApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICApICsgCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJyZWQiLCBub3RjaD1UUlVFKSArIAogICMgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0zMDAsIDEyMDApKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC01LCAyMCkpICsKICBnZW9tX3RleHQoZGF0YSA9IENvdW50X1ZhbHVlcywKICAgICAgICAgICAgYWVzKHkgPSBWYWx1ZV9Db3VudHMsCiAgICAgICAgICAgICAgICBsYWJlbCA9IGZvcm1hdChyb3VuZChWYWx1ZV9Db3VudHMsIGRpZ2l0cyA9IDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnNtYWxsID0gMQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICksCiAgICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgICB2anVzdCA9IC0wLjUKICAgICAgICAgICApICsKICB4bGFiKCJIb3VyIEdyb3VwIikgKyAKICB5bGFiKCJCdXMgTGF0ZW5lc3MgKG1pbnV0ZXMpIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSkpICsgCiAgI3RoZW1lKGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiLCBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBnZ3RpdGxlKGV4cHJlc3Npb24oYXRvcCgiSG93IEVhcmx5L0xhdGUgaXMgdGhlIEJ1cyAoYnkgSG91ciBHcm91cCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGF0b3AoaXRhbGljKCIocG9zaXRpdmUgdmFsdWVzIGFyZSBsYXRlIGFycml2YWxzKSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgKQoKRGVsdFRpbWVfQm94UGxvdAoKYGBgCgoKSW52ZXN0aWdhdGlvbiBvZiBEZWx0YV9UaW1lIChob3cgZWFybHkgb3IgbGF0ZSB0aGUgYnVzIGlzKS4KCkV4cGxvcmluZyAiZXh0cmVtZSIgRGVsdGFfVGltZXMuICBGaXJzdCBsZXQncyBnZXQgc29tZSAicmFuayIgc3RhdHMuCmBgYHtyfQoKVmlldyhEZWx0VGltZV9QY3RpbGVzKQpEZWx0VGltZV9QY3RpbGVzCgoKRGVsdFRpbWVBYnNfTnRpbGUgPC0gYXMuZGF0YS5mcmFtZShhYnMoQWxsRGF5c19OZXdPcmRlciREZWx0YV9UaW1lKSkgJT4lIAogIG11dGF0ZShQY3RpbGUgPSBudGlsZShhYnMoQWxsRGF5c19OZXdPcmRlciREZWx0YV9UaW1lKSwgMTAwKSwKICAgICAgICAgTWluUiA9IG1pbl9yYW5rKGFicyhBbGxEYXlzX05ld09yZGVyJERlbHRhX1RpbWUpKSwKICAgICAgICAgUGN0UiA9IHBlcmNlbnRfcmFuayhhYnMoQWxsRGF5c19OZXdPcmRlciREZWx0YV9UaW1lKSksCiAgICAgICAgIFBjdFJfUm91bmQgPSByb3VuZChQY3RSLCAyKQogICAgICAgICkgCgpjb2xuYW1lcyhEZWx0VGltZUFic19OdGlsZSlbMV0gPC0gIkRlbHRhX1RpbWVfQWJzIgpzdHIoRGVsdFRpbWVBYnNfTnRpbGUpCgpEZWx0VGltZUFic19OdGlsZV9Sb3dzIDwtIG5yb3coRGVsdFRpbWVBYnNfTnRpbGUpCgpWaWV3KHRhaWwoRGVsdFRpbWVBYnNfTnRpbGUsIDUwMCkpCgoKRGVsdFRpbWVBYnNfUGN0aWxlcyA8LSBncm91cF9ieShEZWx0VGltZUFic19OdGlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQY3RSX1JvdW5kCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBzdW1tYXJpc2UoCiAgICBNaW5EZWx0VGltZUF0UGN0aWxlID0gbWluKERlbHRhX1RpbWVfQWJzKSwKICAgIENudHNBdFBjdGlsZSA9IG4oKSwKICAgIFBjdHNBdFBjdGlsZSA9IENudHNBdFBjdGlsZSAvIERlbHRUaW1lX050aWxlX1Jvd3MKICApICU+JSAKICBtdXRhdGUoQ3VtU3VtUEF0UCA9IGN1bXN1bShQY3RzQXRQY3RpbGUpCiAgICAgICAgKQoKVmlldyhEZWx0VGltZUFic19QY3RpbGVzKQpEZWx0VGltZUFic19QY3RpbGVzCgpgYGAKCgpJbnZlc3RpZ2F0aW9uIG9mIERlbHRhX1RpbWUgKGhvdyBlYXJseSBvciBsYXRlIHRoZSBidXMgaXMpLgoKRXhwbG9yaW5nICJleHRyZW1lIiBEZWx0YV9UaW1lcy4gIFRoZW4gbGV0J3MgY2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIG9mIGJ1c2VzIHRoYXQgYXJlIDEwIG1pbnV0ZXMgKG9yIG1vcmUpIGxhdGUvZWFybHkuCmBgYHtyfQoKSHJHcm91cF9EZWx0YVRpbWVfQWxsIDwtIGdyb3VwX2J5KEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudF9UaW1lX0hyR3JvdXAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgCiAgc3VtbWFyaXNlKEV2ZW50QWxsX0NudCA9IG4oKQogICAgICAgICAgICkKCnN0cihIckdyb3VwX0RlbHRhVGltZV9BbGwpClZpZXcoSHJHcm91cF9EZWx0YVRpbWVfQWxsKQoKCkhyR3JvdXBfRGVsdGFUaW1lX0Fib3ZlMTBNaW4gPC0gZmlsdGVyKEFsbERheXNfTmV3T3JkZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFicyhEZWx0YV9UaW1lKSA+PSA2MDAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBncm91cF9ieShFdmVudF9UaW1lX0hyR3JvdXApICU+JSAKICBzdW1tYXJpc2UoRXZlbnRBYm92ZTEwX0NudCA9IG4oKQogICAgICAgICAgICkKCnN0cihIckdyb3VwX0RlbHRhVGltZV9BYm92ZTEwTWluKQpWaWV3KEhyR3JvdXBfRGVsdGFUaW1lX0Fib3ZlMTBNaW4pCgoKSHJHcm91cF9EZWx0YVRpbWVDb21wYXJlIDwtIGlubmVyX2pvaW4oSHJHcm91cF9EZWx0YVRpbWVfQWJvdmUxME1pbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSHJHcm91cF9EZWx0YVRpbWVfQWxsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoIkV2ZW50X1RpbWVfSHJHcm91cCIgPSAiRXZlbnRfVGltZV9Ickdyb3VwIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JSAKICBtdXRhdGUoUGN0RXZlbnRzQWJvdmUxMCA9IEV2ZW50QWJvdmUxMF9DbnQgLyBFdmVudEFsbF9DbnQpCgpWaWV3KEhyR3JvdXBfRGVsdGFUaW1lQ29tcGFyZSkKCmBgYAoKCkludmVzdGlnYXRpb24gb2YgRGVsdGFfVGltZSAoaG93IGVhcmx5IG9yIGxhdGUgdGhlIGJ1cyBpcykuCgpRdWlja2x5IHBsb3QgdGhlc2UgImV4dHJlbWUiIERlbHRhX1RpbWVzLiAKYGBge3J9CgpEZWx0VGltZV9BYm92ZTEwX0NvbHMgPC0gZ2dwbG90KEhyR3JvdXBfRGVsdGFUaW1lQ29tcGFyZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoZmFjdG9yKEV2ZW50X1RpbWVfSHJHcm91cCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBjdEV2ZW50c0Fib3ZlMTAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBnZW9tX2NvbChmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG91ciA9ICJncmV5NjAiLCBzaXplID0gMC4yKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZvcm1hdChyb3VuZChQY3RFdmVudHNBYm92ZTEwLCBkaWdpdHMgPSAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5zbWFsbCA9IDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICApLAogICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgbnVkZ2VfeSA9IChIckdyb3VwX0RlbHRhVGltZUNvbXBhcmUkUGN0RXZlbnRzQWJvdmUxMCAqIC0wLjEpCiAgICAgICAgICAgKSArCiAgIyBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoLTUsIDUpKSArCiAgeGxhYigiSG91ciBHcm91cCIpICsgCiAgeWxhYigiUGVyY2VudCBvZiBBbGwgQnVzIEFycml2YWxzIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1KSkgKwogIGdndGl0bGUoZXhwcmVzc2lvbihhdG9wKCJXaGVuIGlzIGEgQnVzIDEwKyBNaW51dGVzIExhdGUvRWFybHkiCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyAsYXRvcChpdGFsaWMoInBvc2l0aXZlIHZhbHVlcyBhcmUgbGF0ZSBhcnJpdmFscyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICAiIgogICAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICkKCkRlbHRUaW1lX0Fib3ZlMTBfQ29scwoKYGBgCgoKUXVpY2sgaW52ZXN0aWdhdGlvbiBvbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gRHdlbGxfVGltZTIgKHRoZSB0aW1lIGEgYnVzIGlzIGF0IGEgc3RvcCkgYW5kIERlbHRhX1RpbWUgKGhvdyBlYXJseS9sYXRlIHRoZSBidXMgaXMpLgoKQ29ycmVsYXRpb24uCmBgYHtyfQoKRHdlbGxURGVsdGFUX0NvcnIgPC0gYXMubWF0cml4KGNvcih4ID0gQWxsRGF5c19OZXdPcmRlciREd2VsbF9UaW1lMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQWxsRGF5c19OZXdPcmRlciREZWx0YV9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZSA9ICJwYWlyd2lzZSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCkR3ZWxsVERlbHRhVF9Db3JyCgpgYGAKCgpRdWljayBpbnZlc3RpZ2F0aW9uIG9uIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBEd2VsbF9UaW1lMiAodGhlIHRpbWUgYSBidXMgaXMgYXQgYSBzdG9wKSBhbmQgRGVsdGFfVGltZSAoaG93IGVhcmx5L2xhdGUgdGhlIGJ1cyBpcykuCgpOZXh0LCBsZXQncyBnZXQgYSBzYW1wbGUgb2YgZGF0YSBmb3IgcGxvdHRpbmcuIExldCdzIGRvIHRoaXMgZm9yIHRoZSBmdWxsIGRhdGFzZXQgKEFsbERheXNfTmV3T3JkZXIpLgpgYGB7cn0KCkFsbERheXNfTmV3T3JkZXJfMTBQY3RTYW1wIDwtIHNhbXBsZV9mcmFjKEFsbERheXNfTmV3T3JkZXIsIDAuMSkgJT4lIAogIHNlbGVjdChEZWx0YV9UaW1lLAogICAgICAgICBEd2VsbF9UaW1lMgogICAgICAgICkgJT4lIAogIG11dGF0ZShEYXRhU2V0ID0gIkFsbERhdGEiKQoKc3RyKEFsbERheXNfTmV3T3JkZXJfMTBQY3RTYW1wKQoKYGBgCgoKUXVpY2sgaW52ZXN0aWdhdGlvbiBvbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gRHdlbGxfVGltZTIgKHRoZSB0aW1lIGEgYnVzIGlzIGF0IGEgc3RvcCkgYW5kIERlbHRhX1RpbWUgKGhvdyBlYXJseS9sYXRlIHRoZSBidXMgaXMpLgoKTGV0J3MgYWxzbyBnZXQgYSBzYW1wbGUgb2YgZGF0YSBmb3IgcGxvdHRpbmcsIGJ1dCB3aXRoIGEgZGF0c2V0IHRoYXQgcmVtb3ZlcyBvdXRsaWVycy4KYGBge3J9CgpWaWV3KERlbHRUaW1lX1BjdGlsZXMpClZpZXcoRHdlbGxUaW1lMl9QY3RpbGVzKQoKQWxsRGF5c19OZXdPcmRlcl9Ob0V4dHJlbWVzXzEwUGN0U2FtcCA8LSBmaWx0ZXIoQWxsRGF5c19OZXdPcmRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmV0d2VlbihEZWx0YV9UaW1lLCAtNDAyLCAxNzA1KSAmICMgcmVtb3ZlcyBhYm91dCAyJSBvZiBEZWx0YV9UaW1lIHZhbHVlcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHdlZW4oRHdlbGxfVGltZTIsIDEsIDYzKSAgIyByZW1vdmVzIGFib3V0IDIlIG9mIER3ZWxsX1RpbWUyIHZhbHVlcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIAogIHNhbXBsZV9mcmFjKDAuMSkgJT4lIAogIHNlbGVjdChEZWx0YV9UaW1lLAogICAgICAgICBEd2VsbF9UaW1lMgogICAgICAgICkgJT4lIAogIG11dGF0ZShEYXRhU2V0ID0gIk91dGxpZXJzUmVtb3ZlZCIpCgpzdHIoQWxsRGF5c19OZXdPcmRlcl9Ob0V4dHJlbWVzXzEwUGN0U2FtcCkKCmBgYAoKClF1aWNrIGludmVzdGlnYXRpb24gb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIER3ZWxsX1RpbWUyICh0aGUgdGltZSBhIGJ1cyBpcyBhdCBhIHN0b3ApIGFuZCBEZWx0YV9UaW1lIChob3cgZWFybHkvbGF0ZSB0aGUgYnVzIGlzKS4KClBsb3R0aW5nIHRoZSBkYXRhIGZyb20gdGhlIGRhdGFzZXQgdGhhdCBkb2VzIG5vdCByZW1vdmUgb3V0bGllcnMuCmBgYHtyfQoKRHdlbGxURGVsdGFUX1NjYXR0ZXIgPC0gZ2dwbG90KEFsbERheXNfTmV3T3JkZXJfMTBQY3RTYW1wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKER3ZWxsX1RpbWUyLCBEZWx0YV9UaW1lKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBnZW9tX3BvaW50KHNoYXBlID0gMSwgYWxwaGEgPSAwLjUpICsKICBzY2FsZV9zaGFwZShzb2xpZCA9IEZBTFNFKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3VyID0gInJlZCIpICsKICAjIHhsYWIoIlRpbWUgYXQgU3RvcCAoc2VjKSIpICsgCiAgIyB5bGFiKCJMYXRlbmVzcyAoc2VjKSIpICsKICBhbm5vdGF0ZShsYWJlbCA9IGxtX2VxbihkZiA9IEFsbERheXNfTmV3T3JkZXJfMTBQY3RTYW1wLAogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBBbGxEYXlzX05ld09yZGVyXzEwUGN0U2FtcCREZWx0YV9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBBbGxEYXlzX05ld09yZGVyXzEwUGN0U2FtcCREd2VsbF9UaW1lMgogICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICB4ID0gMjIwMCwKICAgICAgICAgICB5ID0gNjAwLAogICAgICAgICAgIGdlb20gPSAidGV4dCIsCiAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgY29sb3VyID0gInJlZCIsCiAgICAgICAgICAgcGFyc2UgPSBUUlVFCiAgICAgICAgICApICsKICBsYWJzKHRpdGxlID0gIkxhdGVuZXNzIHZzIFRpbWUgYXQgU3RvcCIsCiAgICAgICBzdWJ0aXRsZSA9ICIobm8gb3V0bGllcnMgcmVtb3ZlZCkiLAogICAgICAgeCA9ICJUaW1lIGF0IFN0b3AgKHNlYykiLAogICAgICAgeSA9ICJMYXRlbmVzcyAoc2VjKSIKICAgICAgKQogICMgZ2d0aXRsZShleHByZXNzaW9uKGF0b3AoIkxhdGVuZXNzIHZzIFRpbWUgYXQgU3RvcCIKICAjICAgICAgICAgICAgICAgICAgICAgICAgICxhdG9wKGl0YWxpYygiKG5vIG91dGxpZXJzIHJlbW92ZWQpIiksCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIgogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICkKICAjICAgICAgICAgICAgICAgICAgICkKICAjICAgICAgICApCiMgKwojICAgZ2VvbV9qaXR0ZXIoKQoKRHdlbGxURGVsdGFUX1NjYXR0ZXIKCmBgYAoKClF1aWNrIGludmVzdGlnYXRpb24gb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIER3ZWxsX1RpbWUyICh0aGUgdGltZSBhIGJ1cyBpcyBhdCBhIHN0b3ApIGFuZCBEZWx0YV9UaW1lIChob3cgZWFybHkvbGF0ZSB0aGUgYnVzIGlzKS4KClBsb3R0aW5nIHRoZSBkYXRhIGZyb20gdGhlIGRhdGFzZXQgdGhhdCBkb2VzIHJlbW92ZSBvdXRsaWVycy4KYGBge3J9CgpEd2VsbFREZWx0YVRfU2NhdHRlcl9Ob0V4dHJlbWVzIDwtIGdncGxvdChBbGxEYXlzX05ld09yZGVyX05vRXh0cmVtZXNfMTBQY3RTYW1wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoRHdlbGxfVGltZTIsIERlbHRhX1RpbWUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDEsIGFscGhhID0gMC41KSArCiAgc2NhbGVfc2hhcGUoc29saWQgPSBGQUxTRSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG91ciA9ICJibHVlIikgKwogICMgeGxhYigiVGltZSBhdCBTdG9wIChzZWMpIikgKyAKICAjIHlsYWIoIkxhdGVuZXNzIChzZWMpIikgKwogIGFubm90YXRlKGxhYmVsID0gbG1fZXFuKGRmID0gQWxsRGF5c19OZXdPcmRlcl9Ob0V4dHJlbWVzXzEwUGN0U2FtcCwKICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQWxsRGF5c19OZXdPcmRlcl9Ob0V4dHJlbWVzXzEwUGN0U2FtcCREZWx0YV9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBBbGxEYXlzX05ld09yZGVyX05vRXh0cmVtZXNfMTBQY3RTYW1wJER3ZWxsX1RpbWUyCiAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIHggPSA1MCwKICAgICAgICAgICB5ID0gLTQ3NSwKICAgICAgICAgICBnZW9tID0gInRleHQiLAogICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgIGNvbG91ciA9ICJibHVlIiwKICAgICAgICAgICBwYXJzZSA9IFRSVUUKICAgICAgICAgICkgKwogIGxhYnModGl0bGUgPSAiTGF0ZW5lc3MgdnMgVGltZSBhdCBTdG9wIiwKICAgICAgIHN1YnRpdGxlID0gIigyJSBvZiBvdXRsaWVycyByZW1vdmVkKSIsCiAgICAgICB4ID0gIlRpbWUgYXQgU3RvcCAoc2VjKSIsCiAgICAgICB5ID0gIkxhdGVuZXNzIChzZWMpIgogICAgICApCiAgIyBnZ3RpdGxlKGV4cHJlc3Npb24oYXRvcCgiTGF0ZW5lc3MgdnMgVGltZSBhdCBTdG9wIgogICMgICAgICAgICAgICAgICAgICAgICAgICAgLGF0b3AoaXRhbGljKCIoMiUgb2Ygb3V0bGllcnMgcmVtb3ZlZCkiKSwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIiCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAjICAgICAgICAgICAgICAgICAgICAgICAgKQogICMgICAgICAgICAgICAgICAgICAgKQogICMgICAgICAgICkKIyArCiMgICBnZW9tX2ppdHRlcigpCgpEd2VsbFREZWx0YVRfU2NhdHRlcl9Ob0V4dHJlbWVzCgpgYGAKCgpRdWljayBpbnZlc3RpZ2F0aW9uIG9uIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBEd2VsbF9UaW1lMiAodGhlIHRpbWUgYSBidXMgaXMgYXQgYSBzdG9wKSBhbmQgRGVsdGFfVGltZSAoaG93IGVhcmx5L2xhdGUgdGhlIGJ1cyBpcykuCgpQbG90dGluZyB0aGUgZGF0YSBmcm9tIGJvdGggZGF0YXNldHMgdG9nZXRoZXIuCmBgYHtyfQoKQ29tYmluZWREYXRhIDwtIHJiaW5kKEFsbERheXNfTmV3T3JkZXJfMTBQY3RTYW1wLAogICAgICAgICAgICAgICAgICAgICAgQWxsRGF5c19OZXdPcmRlcl9Ob0V4dHJlbWVzXzEwUGN0U2FtcAogICAgICAgICAgICAgICAgICAgICApCgpDb21iaW5lZERhdGEkRGF0YVNldCA8LSBmYWN0b3IoQ29tYmluZWREYXRhJERhdGFTZXQpCgpzdHIoQ29tYmluZWREYXRhKQoKCkR3ZWxsVERlbHRhVF9TY2F0dGVyX0NvbWJpbmVkIDwtIGdncGxvdChDb21iaW5lZERhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IER3ZWxsX1RpbWUyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBEZWx0YV9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IERhdGFTZXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDEsIGFscGhhID0gMC41KSArCiAgc2NhbGVfc2hhcGUoc29saWQgPSBGQUxTRSkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLCA1MDApLCB5bGltID0gYygtMTAwMCwgMjAwMCkKICAgICAgICAgICAgICAgICApICsKICBnZW9tX3Ntb290aChkYXRhID0gZmlsdGVyKENvbWJpbmVkRGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIERhdGFTZXQgPT0gIkFsbERhdGEiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgbWV0aG9kID0gImxtIiwKICAgICAgICAgICAgICBjb2xvdXIgPSAicmVkIgogICAgICAgICAgICAgKSArCiAgZ2VvbV9zbW9vdGgoZGF0YSA9IGZpbHRlcihDb21iaW5lZERhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEYXRhU2V0ID09ICJPdXRsaWVyc1JlbW92ZWQiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgbWV0aG9kID0gImxtIiwKICAgICAgICAgICAgICBjb2xvdXIgPSAiYmx1ZSIKICAgICAgICAgICAgICkgKwogICMgZmFjZXRfd3JhcCggfiBEYXRhU2V0LCBuY29sID0gMikgKwogIGFubm90YXRlKGxhYmVsID0gbG1fZXFuKGRmID0gQWxsRGF5c19OZXdPcmRlcl8xMFBjdFNhbXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IEFsbERheXNfTmV3T3JkZXJfMTBQY3RTYW1wJERlbHRhX1RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IEFsbERheXNfTmV3T3JkZXJfMTBQY3RTYW1wJER3ZWxsX1RpbWUyCiAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIHggPSAzMDAsCiAgICAgICAgICAgeSA9IC02MDAsCiAgICAgICAgICAgZ2VvbSA9ICJ0ZXh0IiwKICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICBjb2xvdXIgPSAicmVkIiwKICAgICAgICAgICBwYXJzZSA9IFRSVUUKICAgICAgICAgICkgKwogIGFubm90YXRlKGxhYmVsID0gbG1fZXFuKGRmID0gQWxsRGF5c19OZXdPcmRlcl9Ob0V4dHJlbWVzXzEwUGN0U2FtcCwKICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQWxsRGF5c19OZXdPcmRlcl9Ob0V4dHJlbWVzXzEwUGN0U2FtcCREZWx0YV9UaW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBBbGxEYXlzX05ld09yZGVyX05vRXh0cmVtZXNfMTBQY3RTYW1wJER3ZWxsX1RpbWUyCiAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgIHggPSAzMDAsCiAgICAgICAgICAgeSA9IC04MDAsCiAgICAgICAgICAgZ2VvbSA9ICJ0ZXh0IiwKICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICBjb2xvdXIgPSAiYmx1ZSIsCiAgICAgICAgICAgcGFyc2UgPSBUUlVFCiAgICAgICAgICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGxhYnModGl0bGUgPSAiTGF0ZW5lc3MgdnMgVGltZSBhdCBTdG9wIiwKICAgICAgIHggPSAiVGltZSBhdCBTdG9wIChzZWMpIiwKICAgICAgIHkgPSAiTGF0ZW5lc3MgKHNlYykiCiAgICAgICkKICAjIGdndGl0bGUoZXhwcmVzc2lvbihhdG9wKCJMYXRlbmVzcyB2cyBUaW1lIGF0IFN0b3AiCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyAsYXRvcChpdGFsaWMoIjIlIG9mIG91dGxpZXJzIHJlbW92ZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICIiCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyAgICAgICkKICAgICAgICAgIyAgICAgICAgICAgICAgICAgKQogICAgICAgICAjICAgICAgICAgICAgKQogICAgICAgICAjICkKIyArCiMgICBnZW9tX2ppdHRlcigpCgpEd2VsbFREZWx0YVRfU2NhdHRlcl9Db21iaW5lZAoKYGBgCgoKCgoKCgoKCgoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLgo=